2011年11月24日 星期四

IR Remote Control LED program

//=========================
//Project:     IR Remote Controller Decode
//Author:      Leo.Tseng
//Date:        2011/11/25
//MCU:         W78E054D
//CRYSTAL:     25Mhz
//Description: Use uart for output, set boudrate=9600,
//             Decode NEC transmission format
//=========================
#include  <reg52.h>
#include  <stdio.h>
// 變數宣告
sbit WAVEFORM_OUT = P2^0;
sbit IR_INT = P3^2;
sbit UP = P1^2;                    // LED1
sbit DOWN = P1^3;                  // LED2
sbit LEFT = P1^4;                  // LED3
sbit RIGHT = P1^5;                 // LED4
unsigned int ir_high;
unsigned int IR_BUFFER[33]=0;
unsigned int PERIOD_HIGH;
int index=0,i,j;
unsigned long ir_data=0;

//副程式宣告
void TIMER1_initinal(int baudrate);
//主程式開始
void main(void)
{
 WAVEFORM_OUT=1;
 PERIOD_HIGH=201;                     // Sample rate 38Khz.
 TIMER1_initinal(9600);               // 使用UART,baudrate=9600

 IT0 = 1;                             // Configure interrupt 0 for falling edge on /INT0 (P3.2)
 EX0 = 1;                             // Enable EX0 Interrupt
 
 TMOD = (TMOD & 0xF0) | 0x0a;         /* Set T/C0 Mode */
 TH0= PERIOD_HIGH;                    // load sampleing rate
 TL0= TH0;                            //
 ET0 = 1;                             /* Enable Timer 0 Interrupts */
 TR0 = 1;                             /* Start Timer 0 Running */
 EA = 1;                              /* Global Interrupt Enable */

 printf("\nPress IR remote controller to decoed\n\n");

 IR_INT=1;
 //WAVEFORM_OUT = IR_INT;
 ir_high=0;

 UP=DOWN=LEFT=RIGHT=0;

 while(1)
  {
  //if(blinking) UP^=DOWN^=LEFT^=RIGHT^=1;
   
   //WAVEFORM_OUT = IR_INT;             // 關閉38K輸出
   if(index==33)
     {
      //printf("index_loop index=%d\n",index);
      TR0=0;
      ET0=0;
      EX0=0;
      EA=0;
      ///*
      for(i=0;i<4;i++)
         for(j=0;j<4;j++)
            {
             IR_BUFFER[33]=IR_BUFFER[8*i+j];             
             IR_BUFFER[8*i+j]=IR_BUFFER[7+8*i-j];
             IR_BUFFER[7+8*i-j]=IR_BUFFER[33];
            }
      for(i=0;i<32;i++)
         {
          if((IR_BUFFER[i]>=18)&&(IR_BUFFER[i]<=28))
            {
             IR_BUFFER[i]=0;
             ir_data=ir_data<<1;
            }
          else if((IR_BUFFER[i]>=60)&&(IR_BUFFER[i]<=70))
                 {
                  IR_BUFFER[i]=1;
                  ir_data=(ir_data<<1)|0x01;
                 }
          printf("%d",IR_BUFFER[i]);
         }
      printf(" < The Binary Code\n");  
      printf("The Hexadecimal Code:%lX \t",ir_data);
      printf("\n\n");
      //*/
     
      /*
      for(i=0;i<32;i++)                       // for debug
        printf("[%d]:%d\n",i,IR_BUFFER[i]);
      */
          
      //============================ 
      switch(ir_data)                        
           {
            case 0x08e614eb:UP^=1;                               // 對應上鍵,亮滅LED1
                      break;
                     
            case 0x08e616e9:DOWN^=1;                            // 對應下鍵,亮滅LED2
                      break;
                     
            case 0x08e61de2:LEFT^=1;                             // 對應左鍵,亮滅LED3
                      break;
                     
            case 0x08e611ee:RIGHT^=1;                            // 對應右鍵,亮滅LED4
                      break;
                     
            case 0x08E65CA3:DOWN^=UP^=1;                         // 對應+鍵,LED做4位元上數計數器
                            LEFT^=(DOWN && UP);
                            RIGHT^=(LEFT && DOWN && UP);
                      break;
                     
            case 0x08E65DA2:DOWN^=!(UP^=1);                      // 對應-鍵,LED做4位元下數計數器 
                            LEFT^=(!DOWN && !UP);
                            RIGHT^=(!LEFT && !DOWN && !UP);
                      break;                            
                     
                                      
            default: break;                
           }
      //============================  
     
      index=0;
      ir_high=0;                     
      TL0=TH0;                            // 重新載入取樣頻率
      TR0=1;
      ET0=1;
      EX0=1;
     }
   EA=1;    
  }
}

//UART副程式
void TIMER1_initinal(int baudrate)      
{
 PCON  = 0x00;                          // PCON: if SMOD=1(b7), Baud Rate is Doubled                         
 SCON  = 0x52;                          // SCON: mode 1, 8-bit UART, enable rcvr                   
 TMOD  = 0x20;                            // TMOD: timer 1, mode 2, 8-bit reload          
 //TH1   = 256-(11059200/384/baudrate);   // TH1:  reload value for baud @ 11.0592MHz, TH=0xFD
 TH1   = 256-(25000000/372/baudrate);     // TH1:  reload value for baud @ 25MHz, TH=0xF9   
 TR1   = 1;                               // TR1:  timer 1 run                             
 //TI    = 1;                             // TI:   set TI to send first char of UART   
}
//計時器0中斷1
void timer0_ISR(void) interrupt 1
{
 WAVEFORM_OUT^=1;
 ir_high++;
 EX0=1;                                   // 外部中斷0致能
}
// INT0中斷0
void EXT_INT0(void) interrupt 0
{
 WAVEFORM_OUT = IR_INT;                   // 關閉38K輸出
 EX0=0;                                   // 外部中斷0禁能
 TR0=0;                                   // 計時器0停止
 ET0=0;                                   // 計時器0中斷禁能
 TL0= TH0;            
 IR_BUFFER[index]=ir_high;                //
 index++;                                 // 指向下一個儲存區
 if((ir_high>=160)&&(ir_high<=180))
  index=0;                                // 前導碼值 68@TH0=120, 167@TH0=200
 ir_high=0;                     
 ET0=1;                                   //                 
 TR0=1;                                   //  
}                     

2011年11月22日 星期二

NEC transmission format IR remote controller decode program

//=========================
//Project:     IR Remote Controller Decode
//Author:      Leo.Tseng
//Date:        2011/11/22
//MCU:         W78E054D
//CRYSTAL:     25Mhz
//Description: Use uart for output, set boudrate=9600,
//             Decode NEC transmission format
//=========================
#include  <reg52.h>
#include  <stdio.h>
// 變數宣告
sbit IR_INT = P3^2;
sbit IR_OUT = P2^0;
unsigned int IR_BUFFER[33]=0;
unsigned int i,j,index=0;
unsigned long ir_data=0;
        
// 副程式宣告
void UART_initinal(int baudrate);
void timer0_RUN(void);

// 主程式開始
void main(void)
{
 UART_initinal(9600);               // 使用UART,baudrate=9600

 IT0 = 1;                             // 設定INT0 (P3.2)為負緣輸入中斷
 EX0 = 1;                             // 致能INT0中斷
 
 TMOD = (TMOD & 0xF0) | 0x01;         // 設定計時器0為模式1
 EA = 1;                              // 總中斷致能啟始
 ET0 = 0;                             // 禁止計時器0產生中斷
 TR0 = 0;                             // 禁止計時器0計數
 
 printf("NEC編碼遙控器解碼程式\n\n");

 //IR_INT=1;
  
 while(1)
  {
   if(index==32)
     {
      TR0=0;                           // 停止計時器0
      ET0=0;                           // 禁止計時器0產生中斷     
      EX0=0;                           // 禁止外部中斷0產生中斷
      EA=0;                            // 禁止所有中斷
      for(i=0;i<4;i++)
         for(j=0;j<4;j++)
            {
             IR_BUFFER[33]=IR_BUFFER[8*i+j];             
             IR_BUFFER[8*i+j]=IR_BUFFER[7+8*i-j];
             IR_BUFFER[7+8*i-j]=IR_BUFFER[33];
            }
      for(i=0;i<32;i++)
         {
          if((IR_BUFFER[i]>=7)&&(IR_BUFFER[i]<=10))
            {
             IR_BUFFER[i]=0;
             ir_data=ir_data<<1;
            }
          else if((IR_BUFFER[i]>=17)&&(IR_BUFFER[i]<=20))
                 {
                  IR_BUFFER[i]=1;
                  ir_data=(ir_data<<1)|0x01;
                 }
          printf("%d",IR_BUFFER[i]);
         }
      printf(" < 二進位碼\n");  
      printf("遙控器16進位全碼:%lX \t",ir_data);
      printf("\n\n");
     
      // 重置所有變數及暫存區及中斷致能
      index=0;
      ir_data=0;
      TH0= 0;                           
      TL0= 0;
      EX0=1; 
     }
   EA=1;
  }
}
// 主程式結束

// UART副程式
void UART_initinal(int baudrate)      
{
 PCON  = 0x00;                          // PCON: if SMOD=1(b7), Baud Rate is Doubled                         
 SCON  = 0x52;                          // SCON: mode 1, 8-bit UART, enable rcvr                   
 TMOD  = (TMOD & 0x0F) | 0x20;            // TMOD: timer 1, mode 2, 8-bit reload          
 //TH1   = 256-(11059200/384/baudrate);   // TH1:  reload value for baud @ 11.0592MHz, TH=0xFD
 TH1   = 256-(25000000/372/baudrate);     // TH1:  reload value for baud @ 25MHz, TH=0xF9   
 TR1   = 1;                               // TR1:  timer 1 run                             
 //TI    = 1;                             // TI:   set TI to send first char of UART   
}
// INT0中斷0
void EXT_INT0(void) interrupt 0
{
 EX0=0;                                   // 外部中斷0禁能
 IR_BUFFER[index]=TH0;                    // 儲存計時器0的計時值
 index++;                                 // 指向下一個暫存區
 if(TH0==109) index=0;                    // 偵測前導碼
 timer0_RUN();                            // 開始計時
}
//Timer0 計時副程式
void timer0_RUN()
{
 TR0=0;                                   // 停止計時器0
 TH0=0;                                   // 重設計時器0
 TL0=0;                                   //
 TR0=1;                                   // 啟動計時器0
 EX0=1;                                   // 外部中斷0重新啟動
}


============= 測試結果 ================

NEC編碼遙控器解碼程式
00001000111001100100011110111000 < 二進位碼
遙控器16進位全碼:8E647B8
00001000111001100100001110111100 < 二進位碼
遙控器16進位全碼:8E643BC
00001000111001100100001010111101 < 二進位碼
遙控器16進位全碼:8E642BD
00001000111001100100000110111110 < 二進位碼
遙控器16進位全碼:8E641BE
00001000111001100100000010111111 < 二進位碼
遙控器16進位全碼:8E640BF
00001000111001100100011010111001 < 二進位碼
遙控器16進位全碼:8E646B9
00001000111001100100010110111010 < 二進位碼
遙控器16進位全碼:8E645BA
00001000111001100100010010111011 < 二進位碼
遙控器16進位全碼:8E644BB
00001000111001100100101010110101 < 二進位碼
遙控器16進位全碼:8E64AB5
00001000111001100100100110110110 < 二進位碼
遙控器16進位全碼:8E649B6
00001000111001100100100010110111 < 二進位碼
遙控器16進位全碼:8E648B7
00001000111001100100111010110001 < 二進位碼
遙控器16進位全碼:8E64EB1
00001000111001100100110110110010 < 二進位碼
遙控器16進位全碼:8E64DB2
00001000111001100100110010110011 < 二進位碼
遙控器16進位全碼:8E64CB3
00001000111001100100101110110100 < 二進位碼
遙控器16進位全碼:8E64BB4
00001000111001100001110011100011 < 二進位碼
遙控器16進位全碼:8E61CE3
00001000111001100001101011100101 < 二進位碼
遙控器16進位全碼:8E61AE5
00001000111001100001100111100110 < 二進位碼
遙控器16進位全碼:8E619E6
00001000111001100001100011100111 < 二進位碼
遙控器16進位全碼:8E618E7
00001000111001100001000011101111 < 二進位碼
遙控器16進位全碼:8E610EF
00001000111001100001010011101011 < 二進位碼
遙控器16進位全碼:8E614EB
00001000111001100001110111100010 < 二進位碼
遙控器16進位全碼:8E61DE2
00001000111001100001010111101010 < 二進位碼
遙控器16進位全碼:8E615EA
00001000111001100001000111101110 < 二進位碼
遙控器16進位全碼:8E611EE
00001000111001100001011011101001 < 二進位碼
遙控器16進位全碼:8E616E9
00001000111001100001111011100001 < 二進位碼
遙控器16進位全碼:8E61EE1
00001000111001100001001011101101 < 二進位碼
遙控器16進位全碼:8E612ED
00001000111001100001111111100000 < 二進位碼
遙控器16進位全碼:8E61FE0
00001000111001100001101111100100 < 二進位碼
遙控器16進位全碼:8E61BE4
00001000111001100001011111101000 < 二進位碼
遙控器16進位全碼:8E617E8
00001000111001100001001111101100 < 二進位碼
遙控器16進位全碼:8E613EC
00001000111001100101110010100011 < 二進位碼
遙控器16進位全碼:8E65CA3
00001000111001100101100010100111 < 二進位碼
遙控器16進位全碼:8E658A7
00001000111001100101010010101011 < 二進位碼
遙控器16進位全碼:8E654AB
00001000111001100101000010101111 < 二進位碼
遙控器16進位全碼:8E650AF
00001000111001100101110110100010 < 二進位碼
遙控器16進位全碼:8E65DA2
00001000111001100101100110100110 < 二進位碼
遙控器16進位全碼:8E659A6
00001000111001100101010110101010 < 二進位碼
遙控器16進位全碼:8E655AA
00001000111001100101000110101110 < 二進位碼
遙控器16進位全碼:8E651AE
00001000111001100101111010100001 < 二進位碼
遙控器16進位全碼:8E65EA1
00001000111001100101101010100101 < 二進位碼
遙控器16進位全碼:8E65AA5
00001000111001100101011010101001 < 二進位碼
遙控器16進位全碼:8E656A9
00001000111001100101001010101101 < 二進位碼
遙控器16進位全碼:8E652AD
00001000111001100101111110100000 < 二進位碼
遙控器16進位全碼:8E65FA0
00001000111001100101101110100100 < 二進位碼
遙控器16進位全碼:8E65BA4
00001000111001100101011110101000 < 二進位碼
遙控器16進位全碼:8E657A8
00001000111001100101001110101100 < 二進位碼
遙控器16進位全碼:8E653AC

2011年11月14日 星期一

EEPROM write/read program II

//=========================
//Project:     EEPROM write/read command program
//Author:      Leo.Tseng
//Date:        2011/11/10
//MCU:         W78E054D
//CRYSTAL:     25Mhz
//Description: Use uart for input/output, set boudrate=9600,
//             Input Hexadecimal data to write to EEPROM
//             and read out for verify
//             EEPROM 24C64 address write is 0xA0, address read is 0xA1
//             Write mode: page write, Read mode: Sequential read.
//=========================
#include  <reg52.h>
#include  <stdio.h>

//副程式宣告
void I2C_START(void);
void I2C_STOP(void);
void I2C_CLOCK(int t);
void I2C_write(unsigned char I2C_DATA,int i);
void delay(unsigned int d);
int S_I2C_ACK(void);
int M_I2C_ACK(void);
int M_I2C_NACK(void);
void TIMER1_initinal(int boudrate);
unsigned char I2C_read(int i);
sbit SDA = P2^0; //SDA
sbit SCL = P2^1; //SCL
//sbit SDA = P0^0; //SDA
//sbit SCL = P0^1; //SCL
//======================================
//主程式開始
void main(void)
{  //====================Begin of Main
 unsigned int data_buf[8]={0};
 unsigned char uart_data[8];
 unsigned char I2C_DATA=0xff;
  unsigned char F_ADDRESS,S_ADDRESS;
  unsigned int i;
  int device_ACK;
  int B_index,E_index,index;
  int Byte_counter;
  unsigned int temp_buf;
    
  TIMER1_initinal(9600);              // 使用UART,baudrate=9600

  printf("\n輸入6個16進制字元,前兩字元為資料,後4字元為寫入起始頁位址: ");
  RI=0;
  TI=0;
  i=0;
  while(1)  
    {
     if(RI == 1)
      {                           // 接收到uart字元
       RI = 0;                      // 清除接收接收旗號,準備接收下一個字元
       uart_data[i] = SBUF;           // 讀取輸入字元
       SBUF = uart_data[i];          // 接收到的字元送回uart
       i++;
      }
     else TI = 0;                     // 準備傳送下個接收字元
    
     if ((i==6)) break;
    }
   
  for(i=0;i<6;i++)                                             // 輸入字元限定判斷與轉換成16進位數值
   {                                                           //
    if((uart_data[i]>='0')&&(uart_data[i]<='9'))               // 限定0~9
     {                                                        //
      data_buf[i]=uart_data[i]-0x30;                          //
     }                                                        //
     else if((uart_data[i]>='A')&&(uart_data[i]<='F'))         // 限定A~F
           {                                                  //
            data_buf[i]=uart_data[i]-0x37;                    //
           }                                                  //
           else if((uart_data[i]>='a')&&(uart_data[i]<='f'))   // 限定a~f
                  {                                            //
                   data_buf[i]=(uart_data[i]-0x57);            //
                  }                                            //   
   }                                                          
                                                                 
 //I2C_DATA=((data_buf[0]<<4)+(data_buf[1]&0x0f));             // 轉換輸入值
 printf("\n按任何鍵開始寫入EEPROM\n");
 _getkey();
                                                                 
 I2C_DATA=((data_buf[0]<<4)+(data_buf[1]& 0x0f));              // 轉換要寫入資料值

 F_ADDRESS=((data_buf[2]<<4)+(data_buf[3]& 0x0f));             // 轉換要寫入的高8位元位址
 S_ADDRESS=((data_buf[4]<<4)+(data_buf[5]& 0x0f));             // 轉換要寫入的低8位元位址
 //B_index=(int)F_ADDRESS*256+(int)S_ADDRESS;                    // 計算要開始寫入的位址
 //printf("\nindex in d =%d\n",B_index);
 //printf("\nindex in x =%x\n",B_index);
 //printf("\nindex in u =%u\n",B_index);
//=========== EEPROM Page Write =========================

 I2C_START();                                                  // 開始I2C command
 delay(5);
 I2C_write(0xa0,8);                                            // 寫入device address write
 device_ACK=S_I2C_ACK();                                       // 取得device 狀態
 if(device_ACK)                 
   {
    device_ACK=0;                                              // 清除ACK旗號
    //printf("Slave device is ACK!!\n\n");          
    I2C_write(F_ADDRESS,8);                                    // 寫入第一字組位址
    device_ACK=S_I2C_ACK();
    device_ACK=0;                                              // 清除ACK旗號
    I2C_write(S_ADDRESS,8);                                    // 寫入第二字組位址
    device_ACK=S_I2C_ACK();
    Byte_counter=0;
   
    while(device_ACK)
         {
          device_ACK=0;                                       // 清除ACK旗號
          I2C_write(I2C_DATA,8);                              // page write data, 寫入資料
          device_ACK=(device_ACK=S_I2C_ACK()&&((Byte_counter<31)? 1 : 0));
          //printf("Byte_counter=%d\n\n",Byte_counter);       //for debug
          Byte_counter++;
          //_getkey();                                          //for debug
         }

    I2C_STOP();                                               // Page write完成,每頁32Byte
    if(Byte_counter==32) printf("\nPage write finished!!\n");
    else printf("\nPage write not finished!!\n");
   }
 else
   {
    printf("Slave device is no ACK!!\n\n") ;                 // 否, device no ACK
   } 
//=========== End of EEPROM Page Write =========================

//=========== EEPROM Sequential Read =========================
  printf("\n輸入8個16進制字元為讀出起始位址和終止位址: ");
  i=0;
  RI=0;
  TI=0;
  while(1)  
    {
     if(RI == 1)
      {                                                    // 接收到uart字元
       RI = 0;                                               // 清除接收接收旗號,準備接收下一個字元
       uart_data[i] = SBUF;                                    // 讀取輸入字元
       SBUF = uart_data[i];                                   // 接收到的字元送回uart
       i++;
      }
     else TI = 0;                                              // 準備傳送下個接收字元
    
     if ((i==8)) break;
    }
   
  for(i=0;i<8;i++)                                             // 輸入字元限定判斷與轉換成16進位數值
   {                                                           //
    if((uart_data[i]>='0')&&(uart_data[i]<='9'))               // 限定0~9
     {                                                        //
      data_buf[i]=uart_data[i]-0x30;                          //
     }                                                        //
     else if((uart_data[i]>='A')&&(uart_data[i]<='F'))         // 限定A~F
           {                                                  //
            data_buf[i]=uart_data[i]-0x37;                    //
           }                                                  //
           else if((uart_data[i]>='a')&&(uart_data[i]<='f'))   // 限定a~f
                  {                                            //
                   data_buf[i]=(uart_data[i]-0x57);            //
                  }                                            //   
   }                                                          
                                                                
 printf("\n按任何鍵開始讀出EEPROM\n");
 _getkey();
                                                                 
 //== 新增程式起始 ==
 F_ADDRESS=((data_buf[4]<<4)+(data_buf[5]&0x0f));              // 轉換要讀出結束位址的高8位元
 S_ADDRESS=((data_buf[6]<<4)+(data_buf[7]&0x0f));              // 轉換要讀出結束位址的低8位元
 E_index=(int)F_ADDRESS*256+(int)S_ADDRESS;                    // 計算要開始讀出的結束位址
 //printf("\nE_index in d =%d\n",E_index);
 //printf("\nE_index in x =%x\n",E_index);
 //printf("\nE_index in u =%u\n",E_index);
//== 新增程式結束 ==
 F_ADDRESS=((data_buf[0]<<4)+(data_buf[1]&0x0f));              // 轉換要讀出起始位址的高8位元
 S_ADDRESS=((data_buf[2]<<4)+(data_buf[3]&0x0f));              // 轉換要讀出起始位址的低8位元
 B_index=(int)F_ADDRESS*256+(int)S_ADDRESS;                    // 計算要開始讀出的起始位址
 //printf("\nB_index in d =%d\n",B_index);
 //printf("\nB_index in x =%x\n",B_index);
 //printf("\nB_index in u =%u\n",B_index);
//== 新增程式起始 ==
 index=E_index-B_index+1;                                      // 計算要開始讀出的總位址數      
// printf("\nindex count in d =%d\n",index);
// printf("\nindex count in x =%x\n",index);
// printf("\nindex count in u =%u\n",index);
//== 新增程式結束 ==
 I2C_START();                                                  // 開始I2C command
 delay(5);
 I2C_write(0xa0,8);                                            // 寫入device address write, DUMMY write
 device_ACK=S_I2C_ACK();                                       // 取得device 狀態
 if(device_ACK)                                                // device address write ACK
   {
    device_ACK=0;                                              // 清除ACK旗號
    I2C_write(F_ADDRESS,8);                                    // First word address, DUMMY write
    device_ACK=S_I2C_ACK();                                    // First word address ACK?
    device_ACK=0;                                              // 清除ACK旗號
    I2C_write(S_ADDRESS,8);                                    // second word address, DUMMY write
    device_ACK=S_I2C_ACK();                                    // second word address ACK?
    if(device_ACK)
     {
      I2C_START();                                            // 開始I2C command
       delay(5);
      I2C_write(0xa1,8);                                      // 寫入device address read,
      device_ACK=S_I2C_ACK();                                 // 取得device 狀態
     }
  
    if(device_ACK)
     {
      for(index=B_index;index<=E_index;index++)
         {
          if(index==E_index)     
            {
             device_ACK=0;
             I2C_DATA=I2C_read(8);                              // 讀取資料
             device_ACK=M_I2C_NACK();
             I2C_STOP();
             //printf("\nData Read Finish!!\n\n");
            }   
          else
             {
              device_ACK=0;
              I2C_DATA=I2C_read(8);                             // 讀取資料
              device_ACK=M_I2C_ACK();
              //printf("R_device_ACK=%d\n\n",device_ACK);       // for debug
             } 
     
//=================Read Data 轉換===============================
    
           if(((I2C_DATA/16)>=10)&&((I2C_DATA/16)<=15))          //資料高半位元組是大於9?
            {
              temp_buf=I2C_DATA/16+0x37;                         //轉換成A~F
              uart_data[0]=(char)temp_buf;                                  
             //printf("\n11_Device Read address is %c\n",uart_data[0]);
             }
           else
              {
               temp_buf=I2C_DATA/16+0x30;                        //資料高半位元組小於等於9,轉換成0~9
               uart_data[0]=(char)temp_buf;                                  
               //printf("\n12_Device Read address is %c\n",uart_data[0]);
              }
  
           if(((I2C_DATA%16)>=10)&&((I2C_DATA%16)<=15))          //資料低半位元組是大於9?
            {
              temp_buf=I2C_DATA%16+0x37;                         //轉換成A~F
              uart_data[1]=(char)temp_buf;                                  
              //printf("\n21_Device Read address is %c\n",uart_data[1]);
             }
           else
              {
               temp_buf=I2C_DATA%16+0x30;                         //資料低半位元組小於等於9,轉換成0~9
               uart_data[1]=(char)temp_buf;                                  
               //printf("\n22_Device Read address is %c\n",uart_data[1]);
              }
      
           if(device_ACK) printf("\n位址0X%X 讀出值: 0x%c%c   ",index,uart_data[0],uart_data[1]);
            else
             {
              printf("\n位址0X%X 讀出值: 0x%c%c   ",index,uart_data[0],uart_data[1]);
              printf("\nData Read Finish!!\n\n");
             }
           _getkey();      
         }
     }
   }                                           
//============ End of EEPROM Random Read =========
} //end of main

//=======================================

//延時副程式
void delay(unsigned int d)
{  
 while (--d);
}

//I2C 開始副程式
//     ______
//SDA        \______
//     _________
//SCL           \_______
//         -| |-- START
void I2C_START(void)
{  
 if (SDA!=1) SDA=1;
 if (SCL!=1) SCL=1;
 delay(1);
 SDA = 0;
 delay(5);
 SCL = 0;
}

//I2C 停止副程式
//              _______
//SDA _________/
//           __________
//SCL ______/
//           -| |-- STOP
void I2C_STOP(void)
{  
 if (SDA!=0) SDA=0;
 if (SCL!=0) SCL=0;
 delay(1);
 SCL = 1;
 delay(4);
 SDA = 1;
 delay(10);
}

//I2C clock 產生副程式
void I2C_CLOCK(int t)
{
 delay(t);
 SCL = 1;      //設定SCL為高位準
 delay(t);
 SCL = 0;      //設定SCL為高位準
}

//I2C write 副程式
void I2C_write(unsigned char I2C_DATA,int i)
{
 //bit data_bit;
 while(i--)
   {
    SDA=(I2C_DATA & 0x80)? 1 : 0;  //取出最高位元,並送至SDA
    delay(1);                      //等待SDA穩定
    SCL = 1;
    delay(5);
    //I2C_CLOCK(5);
    I2C_DATA<<=1;                  //下個資料位元
    SCL = 0;
    //delay(1);
   }
}

//I2C Read副程式
unsigned char I2C_read(int i)
{
 unsigned char SDA_BUF=0x00;
 while(i--)
   {
    SCL = 1;                         //確認SCL=1
    //delay(1);                      //等待SDA穩定
    SDA_BUF = (SDA_BUF << 1)|SDA;    //讀取SDA暫存
    delay(4);
    SCL = 0;
    delay(2);
   }
 //printf("\nR_SDA_BUF=%c\n",SDA_BUF);
 return(SDA_BUF); 
}

//Slave ACK副程式
//          ___________ NO ACK
//SDA _____/ \_________ ACK
//           ____
//SCL ______/    \________
//        -|  b9  |---- ACK bit
int S_I2C_ACK(void)
{  
 SDA=1;
 delay(2);
 SCL=1;
 if(SDA==0)                     // 判斷ack bit是否拉low
  {
   delay(6);
   SCL = 0;
   return 1;                    // 是
  }
  else
   {
    delay(6);
    SCL = 0;
    return 0;                   // 否
   }
 }

//Master ACK副程式
int M_I2C_ACK(void)
{  
 //delay(1);
 SDA=0;                         // Master拉low ack bit
 delay(1);
 SCL=1;
 delay(4);
 //SDA=0;
 SCL=0;
 SDA=1;
 return 1;                      // 是
}
//Master NACK副程式
int M_I2C_NACK(void)
{  
 //delay(1);
 SDA=1;                         // Master拉high ack bit
 delay(1);
 SCL=1;
 delay(4);
 //SDA=0;
 SCL=0;
 return 0;                     // 否
}
//UART副程式
void TIMER1_initinal(int boudrate)      
{
 PCON  = 0x00;                          // PCON: if SMOD=1(b7), Baud Rate is Doubled                         
 SCON  = 0x52;                          // SCON: mode 1, 8-bit UART, enable rcvr                   
 TMOD  = 0x20;                            // TMOD: timer 1, mode 2, 8-bit reload          
 //TH1   = 256-(11059200/384/boudrate);   // TH1:  reload value for baud @ 11.0592MHz, TH=0xFD
 TH1   = 256-(25000000/372/boudrate);     // TH1:  reload value for baud @ 25MHz, TH=0xF9   
 TR1   = 1;                               // TR1:  timer 1 run                             
 //TI    = 1;                             // TI:   set TI to send first char of UART   
}


****************************************************************
Test Result :
****************************************************************

輸入6個16進制字元,前兩字元為資料,後4字元為寫入起始頁位址: 330000
按任何鍵開始寫入EEPROM
Page write finished!!
輸入8個16進制字元為讀出起始位址和終止位址: 0000001f
按任何鍵開始讀出EEPROM
位址0X0 讀出值: 0x33  
位址0X1 讀出值: 0x33  
位址0X2 讀出值: 0x33  
位址0X3 讀出值: 0x33  
位址0X4 讀出值: 0x33  
位址0X5 讀出值: 0x33  
位址0X6 讀出值: 0x33  
位址0X7 讀出值: 0x33  
位址0X8 讀出值: 0x33  
位址0X9 讀出值: 0x33  
位址0XA 讀出值: 0x33  
位址0XB 讀出值: 0x33  
位址0XC 讀出值: 0x33  
位址0XD 讀出值: 0x33  
位址0XE 讀出值: 0x33  
位址0XF 讀出值: 0x33  
位址0X10 讀出值: 0x33  
位址0X11 讀出值: 0x33  
位址0X12 讀出值: 0x33  
位址0X13 讀出值: 0x33  
位址0X14 讀出值: 0x33  
位址0X15 讀出值: 0x33  
位址0X16 讀出值: 0x33  
位址0X17 讀出值: 0x33  
位址0X18 讀出值: 0x33  
位址0X19 讀出值: 0x33  
位址0X1A 讀出值: 0x33  
位址0X1B 讀出值: 0x33  
位址0X1C 讀出值: 0x33  
位址0X1D 讀出值: 0x33  
位址0X1E 讀出值: 0x33  
位址0X1F 讀出值: 0x33  
Data Read Finish!!

輸入6個16進制字元,前兩字元為資料,後4字元為寫入起始頁位址: 88ffe0
按任何鍵開始寫入EEPROM
Page write finished!!
輸入8個16進制字元為讀出起始位址和終止位址: ffe0ffff
按任何鍵開始讀出EEPROM
位址0XFFE0 讀出值: 0x88  
位址0XFFE1 讀出值: 0x88  
位址0XFFE2 讀出值: 0x88  
位址0XFFE3 讀出值: 0x88  
位址0XFFE4 讀出值: 0x88  
位址0XFFE5 讀出值: 0x88  
位址0XFFE6 讀出值: 0x88  
位址0XFFE7 讀出值: 0x88  
位址0XFFE8 讀出值: 0x88  
位址0XFFE9 讀出值: 0x88  
位址0XFFEA 讀出值: 0x88  
位址0XFFEB 讀出值: 0x88  
位址0XFFEC 讀出值: 0x88  
位址0XFFED 讀出值: 0x88  
位址0XFFEE 讀出值: 0x88  
位址0XFFEF 讀出值: 0x88  
位址0XFFF0 讀出值: 0x88  
位址0XFFF1 讀出值: 0x88  
位址0XFFF2 讀出值: 0x88  
位址0XFFF3 讀出值: 0x88  
位址0XFFF4 讀出值: 0x88  
位址0XFFF5 讀出值: 0x88  
位址0XFFF6 讀出值: 0x88  
位址0XFFF7 讀出值: 0x88  
位址0XFFF8 讀出值: 0x88  
位址0XFFF9 讀出值: 0x88  
位址0XFFFA 讀出值: 0x88  
位址0XFFFB 讀出值: 0x88  
位址0XFFFC 讀出值: 0x88  
位址0XFFFD 讀出值: 0x88  
位址0XFFFE 讀出值: 0x88  
位址0XFFFF 讀出值: 0x88  
Data Read Finish!!

輸入6個16進制字元,前兩字元為資料,後4字元為寫入起始頁位址:

2011年11月9日 星期三

EEPROM Write/Read program I

//=========================
//Project:     EEPROM Write/Read program I
//Author:      Leo.Tseng
//Date:        2011/11/02
//MCU:         W78E054D
//CRYSTAL:     25Mhz
//Description: Use uart for input/output, set boudrate=9600,
//             Input Hexadecimal data to write to EEPROM
//             and read out for verify
//             EEPROM 24C64 address write is 0xA0, address read is 0xA1
//             Write mode: Byte write, Read mode: Random read.
//=========================
#include  <reg52.h>
#include  <stdio.h>

//副程式宣告
void I2C_START(void);
void I2C_STOP(void);
void I2C_CLOCK(int t);
void I2C_write(unsigned char I2C_DATA,int i);
void delay(unsigned int d);
int I2C_ACK(void);
void TIMER1_initinal(int boudrate);
unsigned char I2C_read(int i);
sbit SDA = P2^0; //SDA
sbit SCL = P2^1; //SCL
//sbit SDA = P0^0; //SDA
//sbit SCL = P0^1; //SCL
//======================================
//主程式開始
void main(void)
{
 unsigned int data_buf[6]={0};
 unsigned char uart_data[6];
 unsigned char I2C_DATA=0xff;
  unsigned char F_ADDRESS,S_ADDRESS;
  unsigned long i=0;
  int device_ACK;
  int index=0;
  int temp=0;
  unsigned int temp_buf;
    
  TIMER1_initinal(9600);              // 使用UART,baudrate=9600

  printf("\n輸入6個16進制字元,前兩字元為資料,後4字元為寫入起始位址: ");
  RI=0;
  TI=0;
  while(1)  
    {
     if(RI == 1)
      {                           // 接收到uart字元
       RI = 0;                      // 清除接收接收旗號,準備接收下一個字元
       uart_data[i] = SBUF;           // 讀取輸入字元
       SBUF = uart_data[i];          // 接收到的字元送回uart
       i++;
      }
     else TI = 0;                     // 準備傳送下個接收字元
    
     if ((i==6)) break;
    }
   
  for(i=0;i<6;i++)                                             // 輸入字元限定判斷與轉換成16進位數值
   {                                                           //
    if((uart_data[i]>='0')&&(uart_data[i]<='9'))               // 限定0~9
     {                                                        //
      data_buf[i]=uart_data[i]-0x30;                          //
     }                                                        //
     else if((uart_data[i]>='A')&&(uart_data[i]<='F'))         // 限定A~F
           {                                                  //
            data_buf[i]=uart_data[i]-0x37;                    //
           }                                                  //
           else if((uart_data[i]>='a')&&(uart_data[i]<='f'))   // 限定a~f
                  {                                            //
                   data_buf[i]=(uart_data[i]-0x57);            //
                  }                                            //   
   }                                                          
                                                                 
 //I2C_DATA=((data_buf[0]<<4)+(data_buf[1]&0x0f));               // 轉換輸入值
 printf("\n按任何鍵開始寫入EEPROM\n");
 _getkey();
                                                                 
 I2C_DATA=((data_buf[0]<<4)+(data_buf[1]& 0x0f));              // 轉換要寫入資料值

 F_ADDRESS=((data_buf[2]<<4)+(data_buf[3]& 0x0f));             // 轉換要寫入的高8位元位址
 S_ADDRESS=((data_buf[4]<<4)+(data_buf[5]& 0x0f));             // 轉換要寫入的低8位元位址
 index=(int)F_ADDRESS*256+(int)S_ADDRESS;                      // 計算要開始寫入的位址
 //printf("\nindex in d =%d\n",index);
 //printf("\nindex in x =%x\n",index);
 //printf("\nindex in u =%u\n",index);
//=========== EEPROM Byte Write =========================

 I2C_START();                                      // 開始I2C command
 delay(5);
 I2C_write(0xa0,8);                                // 寫入device address write
 device_ACK=I2C_ACK();                             // 取得device 狀態
//printf("device_ACK=%d\n\n",device_ACK);
  if(device_ACK)                 
   {
    device_ACK=0;                                  // 清除ACK旗號
    //printf("Slave device is ACK!!\n\n");          
    I2C_write(F_ADDRESS,8);                        // 寫入第一字組位址
    device_ACK=I2C_ACK();
    device_ACK=0;                                  // 清除ACK旗號
    I2C_write(S_ADDRESS,8);                        // 寫入第二字組位址
    device_ACK=I2C_ACK();
  
  
    device_ACK=0;                                  // 清除ACK旗號
    I2C_write(I2C_DATA,8);                         // byte write data, 寫入資料
    device_ACK=I2C_ACK();
  
    I2C_STOP();                                    // 寫入完成, byte write 需要此停止命令
    if(device_ACK) printf("\nByte write finished!!\n");
    else printf("\nByte write not finished!!\n");
   }
  else
   {
    printf("Slave device is no ACK!!\n\n") ;    // 否, device no ACK
   }
 //========== End of EEPROM Byte Write =========================

//=========== EEPROM Random Read =========================
  printf("\n輸入4個16進制字元為讀出起始位址: ");
  i=0;
  RI=0;
  TI=0;
  while(1)  
    {
     if(RI == 1)
      {                           // 接收到uart字元
       RI = 0;                      // 清除接收接收旗號,準備接收下一個字元
       uart_data[i] = SBUF;           // 讀取輸入字元
       SBUF = uart_data[i];          // 接收到的字元送回uart
       i++;
      }
     else TI = 0;                     // 準備傳送下個接收字元
    
     if ((i==4)) break;
    }
   
   for(i=0;i<4;i++)                                            // 輸入字元限定判斷與轉換成16進位數值
   {                                                           //
    if((uart_data[i]>='0')&&(uart_data[i]<='9'))               // 限定0~9
     {                                                        //
      data_buf[i]=uart_data[i]-0x30;                          //
     }                                                        //
     else if((uart_data[i]>='A')&&(uart_data[i]<='F'))         // 限定A~F
           {                                                  //
            data_buf[i]=uart_data[i]-0x37;                    //
           }                                                  //
           else if((uart_data[i]>='a')&&(uart_data[i]<='f'))   // 限定a~f
                  {                                            //
                   data_buf[i]=(uart_data[i]-0x57);            //
                  }                                            //   
   }                                                          
                                                                
 printf("\n按任何鍵開始寫入EEPROM\n");
 _getkey();
                                                                 
 F_ADDRESS=((data_buf[0]<<4)+(data_buf[1]&0x0f));              // 轉換要讀出的高8位元位址
 S_ADDRESS=((data_buf[2]<<4)+(data_buf[3]&0x0f));              // 轉換要讀出的低8位元位址
 index=(int)F_ADDRESS*256+(int)S_ADDRESS;                      // 計算要開始讀出的位址
 //printf("\nindex in d =%d\n",index);
 //printf("\nindex in x =%x\n",index);
 //printf("\nindex in u =%u\n",index);

 I2C_START();                                                 // 開始I2C command
 delay(5);
 I2C_write(0xa0,8);                                           // 寫入device address write, DUMMY write
 device_ACK=I2C_ACK();                                        // 取得device 狀態
 if(device_ACK)                 
   {
    device_ACK=0;                                             // 清除ACK旗號
    I2C_write(F_ADDRESS,8);                                   // First word address, DUMMY write
    device_ACK=I2C_ACK();
    device_ACK=0;                                             // 清除ACK旗號
    I2C_write(S_ADDRESS,8);                                   // second word address, DUMMY write
    device_ACK=I2C_ACK();
    if(device_ACK)
     {
      I2C_START();                                           // 開始I2C command
       delay(5);
      I2C_write(0xa1,8);                                     // 寫入device address read,
      device_ACK=I2C_ACK();                                  // 取得device 狀態
     
     
      I2C_DATA=I2C_read(8);                                  // 讀取資料
      device_ACK=0;                                          // 清除ACK旗號
      I2C_STOP();                                            // 讀取完成
     }                                           
   }
     
                                   
//Read Data 轉換
   if (((I2C_DATA/16)>=10)&&((I2C_DATA/16)<=15))             //位址高半位元組是大於9?
    {
     temp_buf=I2C_DATA/16+0x37;                              //轉換成A~F
     uart_data[0]=(char)temp_buf;                                  
     //printf("\n11_Device Read address is %c\n",uart_data[0]);
    }
   else
      {
       temp_buf=I2C_DATA/16+0x30;                            //位址高半位元組小於等於9,轉換成0~9
       uart_data[0]=(char)temp_buf;                                  
      //printf("\n12_Device Read address is %c\n",uart_data[0]);
      }
  
   if (((I2C_DATA%16)>=10)&&((I2C_DATA%16)<=15))            //位址低半位元組是大於9?
    {
     temp_buf=I2C_DATA%16+0x37;                             //轉換成A~F
     uart_data[1]=(char)temp_buf;                                  
     //printf("\n21_Device Read address is %c\n",uart_data[1]);
    }
   else
      {
       temp_buf=I2C_DATA%16+0x30;                           //位址低半位元組小於等於9,轉換成0~9
       uart_data[1]=(char)temp_buf;                                  
       //printf("\n22_Device Read address is %c\n",uart_data[1]);
      }
    
   printf("\nDevice Read address is 0x%c%c\n",uart_data[0],uart_data[1]);  
  

// printf("\nR_I2C_DATA=%c\n",I2C_DATA);
//============ End of EEPROM Random Read =========
} //end of main

//=======================================

//延時副程式
void delay(unsigned int d)
{  
 while (--d);
}

//I2C 開始副程式
//     ______
//SDA        \______
//     _________
//SCL           \_______
//         -| |-- START

void I2C_START(void)
{  
 if (SDA!=1) SDA=1;
 if (SCL!=1) SCL=1;
 delay(1);
 SDA = 0;
 delay(5);
 SCL = 0;
}

//I2C 停止副程式
//              _______
//SDA _________/
//           __________
//SCL ______/
//           -| |-- STOP
void I2C_STOP(void)
{  
 if (SDA!=0) SDA=0;
 if (SCL!=0) SCL=0;
 delay(1);
 SCL = 1;
 delay(4);
 SDA = 1;
 delay(10);
}

//I2C clock 產生副程式
void I2C_CLOCK(int t)
{
 delay(t);
 SCL = 1;      //設定SCL為高位準
 delay(t);
 SCL = 0;      //設定SCL為高位準
}

//I2C write 副程式
void I2C_write(unsigned char I2C_DATA,int i)
{
 //bit data_bit;
 while(i--)
   {
    SDA=(I2C_DATA & 0x80)? 1 : 0;  //取出最高位元,並送至SDA
    delay(1);                      //等待SDA穩定
    SCL = 1;
    delay(5);
    //I2C_CLOCK(5);
    I2C_DATA<<=1;                  //下個資料位元
    SCL = 0;
    //delay(1);
   }
}

//I2C ACK副程式
//          ___________ NO ACK
//SDA _____/ \_________ ACK
//           ____
//SCL ______/    \________
//        -|  b9  |---- ACK bit
int I2C_ACK(void)
{  
 SDA=1;
 delay(2);
 SCL=1;
 if(SDA==0)                     // 判斷ack bit是否拉low
  {
   delay(6);
   SCL = 0;
   return 1;                    // 是
  }
  else
   {
    delay(6);
    SCL = 0;
    return 0;                   // 否
   }
 }

//UART副程式
void TIMER1_initinal(int boudrate)      
{
 PCON  = 0x00;                          // PCON: if SMOD=1(b7), Baud Rate is Doubled                         
 SCON  = 0x52;                          // SCON: mode 1, 8-bit UART, enable rcvr                   
 TMOD  = 0x20;                            // TMOD: timer 1, mode 2, 8-bit reload          
 //TH1   = 256-(11059200/384/boudrate);   // TH1:  reload value for baud @ 11.0592MHz, TH=0xFD
 TH1   = 256-(25000000/372/boudrate);     // TH1:  reload value for baud @ 25MHz, TH=0xF9   
 TR1   = 1;                               // TR1:  timer 1 run                             
 //TI    = 1;                             // TI:   set TI to send first char of UART   
}

//I2C Read副程式
unsigned char I2C_read(int i)
{
 unsigned char SDA_BUF=0x00;
 while(i--)
   {
    SCL = 1;                         //確認SCL=1
    //delay(1);                      //等待SDA穩定
    SDA_BUF = (SDA_BUF << 1)|SDA;    //讀取SDA暫存
    delay(4);
    SCL = 0;
    delay(2);
   }
 //printf("\nR_SDA_BUF=%c\n",SDA_BUF);
 return(SDA_BUF); 
}