2014年12月29日 星期一

Raspberry Pi b+ 用 Python 控制 LCD 16x2 (HD44780) 教學 Part 1 硬體設定篇


在玩Raspberry Pi的時候,常常會有需要顯示一些簡單文字訊息的需求。像是開機抓到動態IP位置的時候顯示出來,方便遠端ssh登入。

這個時候用LCD螢幕線得太大又太笨重,用UART又需要準備一條USB-TTL的轉接線用電腦來登入,整個弄得非常的繁雜。所以這種時候就需要下面這個東西--兩行十六字的 LCD 顯示模組:

在電子材料行裡可以用便宜的價格輕易買到,去Google的話常常會被提到的型號或關鍵字不是 HD4478 就是 1602 (16x2十六個字兩行)。雖然型號上有點小差異但是控制指令都一樣。而傳輸資料介面除了基本款的 16 pin腳的版本外還有I2C介面。網路上也有人利用位移暫存器來間接控制基本款的 16 pin腳,這種的方式就以後有時間再來寫了。






2014年12月12日 星期五

LIRC 紅外線解碼程式解說


每一Bit 的傳送,都是38KHZ的載波頻率在發送.

NEC Infrared Protocol 

  • A 9ms leading pulse burst (16 times the pulse burst length used for a logical data bit)
  • A 4.5ms space
  • The 8-bit address for the receiving device
  • The 8-bit logical inverse of the address
  • The 8-bit command
  • The 8-bit logical inverse of the command
  • Final 562.5µs pulse burst to show end of message transmission.
  • Logical '0' – a 562.5µs pulse burst followed by a 562.5µs space, with a total transmit time of 1.125ms
  • Logical '1' – a 562.5µs pulse burst followed by a 1.6875ms space, with a total transmit time of 2.25    

Pulse 係由很多 on/off 交替的訊號所組成:
  • Carrier frequency = 38kHz
  • duty factor = 1/3
  • period = 26.5us

image









16 bits for the address (address + inverse) require 27ms to transmit time .and the 16 bits for the command (command + inverse) also require 27ms to transmit time.  
because (address + address inverse) or (command+command inverse) will always contain 8 '0's  and 8 '1's    so (8 * 1.125ms) + (8 * 2.25ms) == 27 ms . 
according to this total time required to transmit the frame is (9ms +4.5ms +27ms+27ms) = 67.5 ms. 


 If the key on the remote controller is kept depressed, a repeat code will be issued, typically around 40ms after the pulse burst that signified the end of the message. A repeat code will continue to be sent out at 108ms intervals, until the key is finally released. The repeat code consists of the following, in order:






if user keeps the key depressed the repeat codes keep coming

==========
static irqreturn_t cir_irq_handler (int irq, void *dev_id, struct pt_regs *regs)
{
    struct timeval tv;
    long deltv;
    int data;
    struct cir_device_data *dev;
    
    dev = (struct cir_device_data *)dev_id;
    
    /* get current time */
    do_gettimeofday(&tv);
    
    if(dev->ir_state == IR_STATE_0) {
        dev->ir_state = IR_STATE_1;
        /* Initializate ir variable */
        dev->ir_count = 0; 
        dev->complete_bits = 0;
        
        /* Configure to generate an interrupt on rising edge
         * Wait 9ms pre-pulse.   
         */
        set_irq_type(gpio_to_irq(CIR_GPIO), IRQT_RISING);
    } else {
        deltv = tv.tv_sec - dev->lasttv.tv_sec;
        
        /* calc time since last interrupt in microseconds */
        data = (int) (deltv*1000000 + tv.tv_usec - dev->lasttv.tv_usec);
        decode_process(dev, data);
    }
    
    /* restore time */
    dev->lasttv = tv;
    
    return IRQ_HANDLED;
}

static int check_bit(int interval)
{
    int bit = 0;

    /* if interval is 1.12ms(+-20%) then bit 0 */
    if(interval > 896 && interval < 1344) 
        bit = 0;
    /* if interval is 2.25ms(+-20%) then bit 1 */
    else if(interval > 1800 && interval < 2700)
        bit = 1;
    else
    /* invalid data bit */    
        bit = -1;  
    
    return bit;
}

static void decode_process(struct cir_device_data *dev, int interval)
{
    int bitvalue = 0;
    
    switch(dev->ir_state){
        case IR_STATE_1:
            /* Configure to generate an interrupt on falling edge
              * decision 9ms pre-pulse, within a +-20% range of the nominal value
              * 9000 - (9000*0.2) = 7200, 9000+(9000*0.2) = 9900
              */
            set_irq_type(gpio_to_irq(CIR_GPIO), IRQT_FALLING);
            if(interval > 7200 && interval < 10800) 
                dev->ir_state = IR_STATE_2; // pre-pulse detected.
            else 
                dev->ir_state = IR_STATE_0; // exit with error, return state_0
            break;
        case IR_STATE_2:
           /* decision long interval(4.5ms) or short interval (2.25ms)
             * long interval is normal message, short interval is repetition code.
             * 4500 - (4500*0.2) = 3600, 4500 + (4500*0.2) = 5400
             * 2250 - (2250*0.2) = 1800, 2250 + (2250*0.2) = 2700
             */
            if(interval > 3600 && interval < 5400) {  
                dev->ir_state = IR_STATE_3; 
            } else if(interval > 1800 && interval < 2700) {
                /* driver not supported repetition. 
                   * Return state_0
                   */
                dev->ir_state = IR_STATE_0; //repeat state.
            } else {
                dev->ir_state = IR_STATE_0;     // exit with error, return state_0
                printk(KERN_DEBUG "CIR:exit with error!\n");
            }
            break;
        case IR_STATE_3:
           /* 32 bits entire message receiving
             */
             bitvalue = check_bit(interval);
             if(bitvalue < 0) {
                 /* invalid data bit */ 
                 dev->ir_state = IR_STATE_0;
             } else {
                 dev->complete_bits <<= 1;
                 dev->complete_bits |= bitvalue;
                 dev->ir_state = IR_STATE_3;
                 dev->ir_count++;
                 
                 if(dev->ir_count >= CIR_DATA_BITS) {
                     /* receiving complete */ 
                     dev->ir_state = IR_STATE_0;
                     /* store to buffer */
                     dev->buff[dev->head] = dev->complete_bits;
                    dev->head = (dev->head + 1) % CIR_BUFFER_SIZE;
                     wake_up_interruptible(&dev->waitq);
                 } 
             }
            break;
        default:
            break;
    }
}


2014年12月11日 星期四

Raspberry pi 遠端家電控制



本實驗主要是學習Linux SPI Driver 並驅動 TI CC2500  RF module以達到RF雙向通訊目的,並學習如何自訂封包格式與通訊協定. Pi會接收來自其他遠端裝置傳送過來的封包,其封包內含遠端AD轉換後VR數值, Pi會判斷 VR大於512則使Relay電路開, 反之VR小於512,使Relay電路關 ,即可達到遠端家電控制的功能.