2011年10月31日 星期一

PWM generation

//=========================
//Project:     PWM generation
//Author:      Leo.Tseng
//Date:        2011/10/28
//MCU:         W78E054D
//CRYSTAL:     25Mhz
//Description: Use uart for input/output, set boudrate=9600,
//             Press "a" to increase PWM high duty, Press "d" to
//             decrease PWM high duty.
//             initination is working in 20% duty.
//=========================
#include  <reg52.h>
#include  <stdio.h>
void uart_initinal(int boudrate);
int TIMES=65536;     // 16bit counter 
int FREQ=10400;      // 200HZ = 10400 機械週期
int PWMHIGH=2080;    // 高電位佔20%=10400*0.2=2080個機械週期
int PWMLOW=8320;     // 低電位佔80%=10400*0.8=8320個機械週期
int PERIOD;
char ch;
sbit PWMOUT = P1^2;
sbit PWMOUT1 = P2^0;
sbit PWMOUT2 = P2^1;
//------------------------------------------------
//MAIN C function
//------------------------------------------------
void main (void)
{
 uart_initinal(9600);              // 起始 UART 設定,baudrate=9600
 //PWMOUT = 0;
 TMOD = (TMOD & 0xF0) | 0x01;      // 設定 T/C0 Mode
 PERIOD = TIMES-PWMHIGH;
 TH0 = PERIOD/256;
 TL0 = PERIOD%256;
 ET0 = 1;                         // 致能 Timer 0 Interrupts
 TR0 = 1;                         // 啟動 Timer 0 計時
 EA = 1;                          // Global Interrupt Enable
 PWMOUT = 1;
 PWMOUT1 = 1;
 PWMOUT2 = 1;

 printf("按 ""a"" 增加PWM工作週期20%%,按 ""d"" 減少PWM工作週期20%%\n");          //顯示操作訊息
 //printf("Press ""a"" to increase duty cycle, ""d"" to decrease duty cycle\n"); //顯示操作訊息
 while (1)
   {
    switch (ch=_getkey())                         
      {
       case '+':                                    // 增加高電位20/%
       case 'A':                                   //
       case 'a':if(PWMHIGH==300)                    //
                   PWMHIGH=2080;
                else if(PWMHIGH <= 6240)        
                        PWMHIGH+=2080;                       
                     else if(PWMHIGH >= 8320)
                            PWMHIGH=10100;
               
                PWMLOW=FREQ-PWMHIGH;
                //printf("a_PWMHIGH is %u\n",PWMHIGH);
                break;
      
       case '-':                                    // 減少高電位20/%
       case 'D':                                   //
       case 'd':if(PWMHIGH==10100)                  //
                  PWMHIGH=8320;
                else if(PWMHIGH >= 4160)
                       PWMHIGH-=2080;                        
                     else if(PWMHIGH <= 2080)
                            PWMHIGH=300;
               
                PWMLOW=FREQ-PWMHIGH;
                //printf("d_PWMHIGH is %u\n",PWMHIGH);
                break;
                
       default: break;                
      }
   }
}

//UART副程式使用timer1
void uart_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  = (TMOD & 0x0f) | 0x20;                  // TMOD: timer 1, mode 2, 8-bit reload; keeps timer0 default.        
 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   
}
//計時器0中斷1
void timer0_ISR(void) interrupt 1
{
 if(PWMOUT==1)
  {
   TR0=0;
   PERIOD = TIMES-PWMLOW;                    
   TH0= PERIOD/256;
   TL0= PERIOD%256;
   TR0=1;
   PWMOUT=0;
   PWMOUT1=0;
   PWMOUT2=0;
  }
  else
   {
     TR0=0;
     PERIOD = TIMES-PWMHIGH;                    
     TH0= PERIOD/256;
     TL0= PERIOD%256;
     TR0=1;
     PWMOUT=1;
     PWMOUT1=1;
     PWMOUT2=1;
    }
}

2011年10月24日 星期一

Auto detect I2C slave device read/write address program

//=========================
//Project:     I2C device read/write address detect program
//Author:      Leo.Tseng
//Date:        2011/10/20
//MCU:         W78E054D
//CRYSTAL:     25Mhz
//Description: Use uart for input/output, set boudrate=9600,
//             auto detect I2C device read/write address.
//=========================
#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);

sbit SDA = P2^0; //SDA
sbit SCL = P2^1; //SCL
//======================================
//主程式開始
void main(void)
{
 unsigned char uart_data[6];
 unsigned int data_buf[6]={0};
 int i=0;
 int index=0;
 int temp=0;
  unsigned char I2C_DATA=0xff;
  int device_ACK;
  unsigned int temp_buf;
    
  TIMER1_initinal(9600);                           // 使用UART,baudrate=9600
 
  printf("\nPress any key to start detect device I2C address!!");
  _getkey();                                       // 等待任何按鍵
  printf("\n\n");  
for (i=0;i<=I2C_DATA;i++)
{
 I2C_START();                                      // 開始I2C command
 
 delay(5);

 I2C_write(i,8);                                   // 寫入device address

 device_ACK=I2C_ACK();                             // 取得device ACK 狀態
 
 I2C_STOP();                                       // 停止I2C command

 if(device_ACK)                                    // 儲存 device ACK address
  {
   data_buf[index]=i;
//   printf("\nACK ADDRESS%d is %d",index,data_buf[index]);
   temp=index++;
  }
}
//index=0;
//===== Address轉換成字元顯示 ==========
 for(index=0;index<=temp;index++)                                  
  {
   if(data_buf[index]& 0x01)                                        //Read address 轉換
    {
     if (((data_buf[index]/16)>=10)&&((data_buf[index]/16)<=15))    //位址高半位元組是大於9?
      {
       temp_buf=data_buf[index]/16+0x37;                            //轉換成A~F
       uart_data[0]=(char)temp_buf;                                  
//       printf("\n11_Device Read address is %c\n",uart_data[0]);
      }
      else
       {
        temp_buf=data_buf[index]/16+0x30;                           //位址高半位元組小於等於9,轉換成0~9
       uart_data[0]=(char)temp_buf;                                  
//        printf("\n21_Device Read address is %c\n",uart_data[0]);
       }
     temp_buf=data_buf[index]%16+0x30;                              //位址低半位元組轉換成0~9
     uart_data[1]=(char)temp_buf;                                  
     printf("\nDevice Read address is 0x%c%c\n",uart_data[0],uart_data[1]);  
    }
    else                                                            //Write address 轉換
     {
       if (((data_buf[index]/16)>=10)&&((data_buf[index]/16)<=15))  //位址高半位元組是大於9?
        {
         temp_buf=data_buf[index]/16+0x37;                          //轉換成A~F
         uart_data[0]=(char)temp_buf;                     
        }
        else
         {
          temp_buf=data_buf[index]/16+0x30;                        //位址高半位元組小於等於9,轉換成0~9
         uart_data[0]=(char)temp_buf;                                      
         }
     temp_buf=data_buf[index]%16+0x30;                             //位址低半位元組轉換成0~9
     uart_data[1]=(char)temp_buf;                                  
     printf("\nDevice Write address is 0x%c%c\n",uart_data[0],uart_data[1]);  
    }
  }
}
//=======================================

//延時副程式
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   
}

2011年10月18日 星期二

I2C device read/write command program

//=========================
//Project:         I2C device read/write command program
//Author:         Leo.Tseng
//Date:            2011/09/30
//MCU:          W78E054D
//CRYSTAL: 25Mhz
//Description: Use uart for input/output, set boudrate=9600,
//                   input Hexadecimal data as your I2C device
//                   read/write address.
//=========================
#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);
sbit SDA = P2^0; //SDA
sbit SCL = P2^1; //SCL
//======================================
//主程式開始
void main(void)
{
 unsigned char uart_data[2];
 unsigned int data_buf[2]={0,0};
 int i=0;
  unsigned char I2C_DATA=0xff;
  int device_ACK;
    
  TIMER1_initinal(9600);                    // 使用UART,baudrate=9600
  printf("\nInput Device Address : ");
  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==2)) break;
    }
   
  printf("\nEnd!!\n");
 
  for(i=0;i<2;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));   // 轉換輸入值

 I2C_START();                                                              // 開始I2C command
 
 delay(5);

 I2C_write(I2C_DATA,8);                                            // 寫入device address

 device_ACK=I2C_ACK();                                         // 取得device 狀態
 
 I2C_STOP();                                                              // 停止I2C command

 //printf("device_ACK=%d\n\n",device_ACK);

 if(device_ACK)                                                          // 判斷device是否有回應
    printf("Slave device is ACK!!\n\n");                         // 是, device ACK
  else printf("Slave device is no ACK!!\n\n") ;              // 否, device no ACK
 //printf("I2C stop!!\n");
}
//=======================================

//延時副程式
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(5);
 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-(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   
}