2011年12月20日 星期二

PWM generation for STEP motor control

//=========================
//Project:     PWM generation for STEP motor control
//Author:      Leo.Tseng
//Date:        2011/12/21
//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.
//             PWM will control 3-wire step motor.
//=========================
#include  <reg52.h>
#include  <stdio.h>
void uart_initinal(int baudrate);
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,n_SCAN;
char ch;
sbit SCAN0 = P1^2;
sbit SCAN1 = P1^3;
sbit SCAN2 = P1^4
//------------------------------------------------
//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;                          // 全部致能始動
 SCAN0 = 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())                         
      {
       // 增加高電位20/%
       case 'A':                                   //
       case 'a':if(PWMHIGH==300)                    //
                   PWMHIGH=2080;
                else if(PWMHIGH <= 6240)        
                        PWMHIGH+=2080;                       
                     else if(PWMHIGH >= 8320)
                            PWMHIGH=10100;         // 最高duty cycle限制97%
               
                PWMLOW=FREQ-PWMHIGH;
                //printf("a_PWMHIGH is %u\n",PWMHIGH);
                break;
      
       // 減少高電位20/%
       case 'D':                                   //
       case 'd':if(PWMHIGH==10100)                  //
                  PWMHIGH=8320;
                else if(PWMHIGH >= 4160)
                       PWMHIGH-=2080;                        
                     else if(PWMHIGH <= 2080)
                            PWMHIGH=300;           // 最低duty cycle限制97%
               
                PWMLOW=FREQ-PWMHIGH;
                //printf("d_PWMHIGH is %u\n",PWMHIGH);
                break;
                
       default: break;                
      }
   }
}

//UART副程式使用timer1
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; keeps timer0 default.        
TH1   = 256-(25000000/372/baudrate);           // TH1:  reload value for baud @ 25MHz, TH=0xF9
 //TH1= 256-(11059200/384/baudrate);  
 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((SCAN0==1)&&(SCAN1==1)&&(SCAN2==1)&&(n_SCAN==0))
  {
   TR0=0;
   PERIOD = TIMES-PWMLOW;                    
   TH0= PERIOD/256;
   TL0= PERIOD%256;
   TR0=1;
   SCAN0=0;
 
  }
 else if((SCAN0==0)&&(SCAN1==1)&&(SCAN2==1)&&(n_SCAN==0))
   {
     TR0=0;
     PERIOD = TIMES-PWMHIGH;                    
     TH0= PERIOD/256;
     TL0= PERIOD%256;
     TR0=1;
     SCAN0=1;
     n_SCAN=1;
    }
   
 if((SCAN1==1)&&(SCAN0==1)&&(SCAN2==1)&&(n_SCAN==1))
  {
   TR0=0;
   PERIOD = TIMES-PWMLOW;                    
   TH0= PERIOD/256;
   TL0= PERIOD%256;
   TR0=1;
   SCAN1=0;
 
  }
 else if((SCAN1==0)&&(SCAN0==1)&&(SCAN2==1)&&(n_SCAN==1))
   {
     TR0=0;
     PERIOD = TIMES-PWMHIGH;                    
     TH0= PERIOD/256;
     TL0= PERIOD%256;
     TR0=1;
     SCAN1=1;
     n_SCAN=2;
    }  
   
 if((SCAN2==1)&&(SCAN0==1)&&(SCAN1==1)&&(n_SCAN==2))
  {
   TR0=0;
   PERIOD = TIMES-PWMLOW;                    
   TH0= PERIOD/256;
   TL0= PERIOD%256;
   TR0=1;
   SCAN2=0;
 
  }
 else if((SCAN2==0)&&(SCAN0==1)&&(SCAN1==1)&&(n_SCAN==2))
   {
     TR0=0;
     PERIOD = TIMES-PWMHIGH;                    
     TH0= PERIOD/256;
     TL0= PERIOD%256;
     TR0=1;
     SCAN2=1;
     n_SCAN=0;
    }       
   
}

===================================================================

2011年12月8日 星期四

NEC protocol IR remote TX program

//=========================
//Project:     NEC protocol TX
//Author:      Leo.Tseng
//Date:        2011/12/09
//MCU:         W78E054D
//CRYSTAL:     25Mhz
//Description: Use uart for input/output, set boudrate=9600,
//             Press Keypad to transmit NEC protocol code
//             SW20=0x08E647B8, power key.
//             SW15=0x08E618E7, channel up.
//             SW19=0x08E610EF, channel down.
//=========================
#include  <reg52.h>
#include  <stdio.h>
void uart_initinal(int boudrate);

int PERIOD,i;
unsigned KEY,temp;
unsigned long ir_data;

sbit PWMOUT = P3^2;
//sbit PWMOUT1 = P2^0;
//sbit PWMOUT2 = P2^1;
sbit SCAN0 = P2^7;                 // KEY SCAN0
sbit SCAN1 = P2^6;                 // KEY SCAN1
sbit SCAN2 = P2^5;                 // KEY SCAN2
sbit SCAN3 = P2^4;                 // KEY SCAN3
sbit DET3 = P2^3;                  // KEY DETECT0, always high
sbit DET2 = P2^2;                  // KEY DETECT2
sbit DET1 = P2^1;                  // KEY DETECT1
sbit DET0 = P2^0;                  // KEY DETECT0

//副程式宣告
void TIMER1_initinal(int baudrate);
void delay (int j);
void NEC_LEADER_CODE(void);
void NEC_low(void);
void NEC_high(void);
void NEC_stop(void);
//------------------------------------------------
//MAIN C function
//------------------------------------------------
void main (void)
{
 uart_initinal(9600);              // 起始 UART 設定,baudrate=9600

 TMOD = (TMOD & 0xF0) | 0x02;      // 設定 T/C0 Mode
 PERIOD = 200;
 TH0 = PERIOD;
 TL0 = TH0;
// ET0 = 1;                          // 致能 Timer 0 Interrupts
// TR0 = 1;                          // 啟動 Timer 0 計時
 EA = 1;                             // 全部致能始動
 PWMOUT = 0;
 SCAN0=0;
 SCAN1=SCAN2=SCAN3=1;
 DET3=DET2=DET1=DET0=1;
 //ir_data = 0x1067E21D; // for transmission 1
 //ir_data = 0xB847E608; // for transmission 2

 printf("NEC編碼紅外線發射程式\n");    // 顯示操作訊息

 while (1)
   {
    if((P2&0x0F)!=0x0F)                // 偵測是否按按鍵?
    {
      temp=P2&0xFF;                    // 第一次儲存按鍵值
      delay(6000);                     // 延遲 0.48us*6000=2.88ms,防彈跳調整
      KEY=P2&0xFF;                     // 第二次讀取按鍵值
      if(KEY&&temp)                    // 判別是否為按鍵
        {                            
     /* 
         ET0 = 1;
         TR0 = 1;
         // ***** transmission 1 *****
         NEC_LEADER_CODE();     
         NEC_low();NEC_low();NEC_low();NEC_high();    // 1:0001 > 8
         NEC_low();NEC_low();NEC_low();NEC_low();     // 0:0000 > 0
         NEC_low();NEC_high();NEC_high();NEC_low();   // 6:0110 > 6
         NEC_low();NEC_high();NEC_high();NEC_high();  // 7:0111 > E
         NEC_high();NEC_high();NEC_high();NEC_low();  // E:1110 > 7
         NEC_low();NEC_low();NEC_high();NEC_low();    // 2:0010 > 4
         NEC_low();NEC_low();NEC_low();NEC_high();    // 1:0001 > 8
         NEC_high();NEC_high();NEC_low();NEC_high();  // D:1101 > B
         NEC_stop();                                  // 停止位元
         //PWMOUT=0;
         ET0 = 0;
         TR0 = 0;
         delay(11030);                                // 補足108ms
         //ET0 = 1;
         //TR0 = 1; 
     */
         switch(KEY)                         
             {
              case 0x7B: printf("SW20 pressed, code=0x7B\n");
                        ir_data = 0xB847E608;  // SW20,等於 0x08E647B8
                        break;
                        
              case 0x7D: printf("SW15 pressed, code=0x7D\n");
                        ir_data = 0xE718E608;  // SW15,等於 0x08E618E7
                        break;
                 
              case 0x7E: printf("SW19 pressed, code=0x7E\n");
                        ir_data = 0xEF10E608;  // SW19,等於 0x08E610EF
                        break;
                                             
                                           
              default: break;                
             }
        
      // ******* transmission 2 ********
         NEC_LEADER_CODE();
          for(i=0;i<32;i++ )     
           {
            if(ir_data & 0x0001)
             {
              //printf("1");      // 除錯用
              NEC_high();
             }
             else
                {
                 //printf("0");   // 除錯用
                 NEC_low();
                }
           ir_data=ir_data>>1;
          }
         NEC_stop();
         //PWMOUT=0;
         ET0 = 0;
         TR0 = 0;
         delay(11030);                                // 補足108ms
         //ET0 = 1;
         //TR0 = 1; 
        }
    }  
   } 
}

//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, 產生38Khz 載波
void timer0_ISR(void) interrupt 1              
{
   PWMOUT^=1;   // 設為高電位
   PWMOUT&=1;
   PWMOUT&=1;
   PWMOUT&=1;
   PWMOUT&=1;
   PWMOUT&=1;
   PWMOUT^=1;   // 設為低電位
   PWMOUT&=1;
   PWMOUT&=1;
   PWMOUT&=1;
   PWMOUT&=1;
   PWMOUT&=1;
   //PWMOUT&=1;
}

void delay (int j)
{
 while(j)
  j--;
}

// NEC前導碼: 9ms高電位, 4.5ms低電位
void NEC_LEADER_CODE(void)
{
 ET0=1;
 TR0=1;
 //PWMOUT1=1; // 除錯用
 delay(336);
// PWMOUT1=0; // 除錯用
 ET0 = 0;
 TR0 = 0;
 delay(1170);
}
// NEC碼0: 0.56ms高電位, 0.56ms低電位
void NEC_low(void)
{
 ET0=1;
 TR0=1;
 //PWMOUT1=1; // 除錯用
 delay(19);
 //PWMOUT1=0; // 除錯用
 ET0 = 0;
 TR0 = 0;
 delay(140);   
}
// NEC碼1: 0.56ms高電位, 1.69ms低電位
void NEC_high(void)
{
 ET0=1;
 TR0=1;
 //PWMOUT1=1; // 除錯用
 delay(19);
 //PWMOUT1=0; // 除錯用
 ET0 = 0;
 TR0 = 0;
 delay(440); 
}
// NEC碼,停止位元: 0.56ms高電位
void NEC_stop(void)
{      
 ET0 = 1;
 TR0 = 1;
 //PWMOUT1=1; // 除錯用
 delay(19);
 //PWMOUT1=0; // 除錯用
 ET0 = 0;
 TR0 = 0;
}      

// =====    Test Result ========================                 


SW15, Code : 0x08E618E7

 SW19, Code : 0x08E610EF


SW20, Code : 0x08E647B8






2011年12月5日 星期一

Key pad detect program

//=========================
//Project:    Key pad detect program
//Author:      Leo.Tseng
//Date:        2011/12/06
//MCU:         W78E054D
//CRYSTAL:     25Mhz
//Description: Use uart for output, set boudrate=9600,
//             Decode KEY pad, this program could support
//             4X4 KEY pad array.
//=========================
#include  <reg52.h>
#include  <stdio.h>
// 變數宣告

sbit UP = P1^2;                    // LED1
sbit DOWN = P1^3;                  // LED2
sbit LEFT = P1^4;                  // LED3
sbit RIGHT = P1^5;                 // LED4
sbit SCAN0 = P2^7;                 // KEY SCAN0
sbit SCAN1 = P2^6;                 // KEY SCAN1
sbit SCAN2 = P2^5;                 // KEY SCAN2
sbit SCAN3 = P2^4;                 // KEY SCAN3
sbit DET3 = P2^3;                  // KEY DETECT0, always high
sbit DET2 = P2^2;                  // KEY DETECT2
sbit DET1 = P2^1;                  // KEY DETECT1
sbit DET0 = P2^0;                  // KEY DETECT0
int n_SCAN;
int TIMES=65536;                   // 16位元計數器 
int PWMHIGH=1;                 
int PWMLOW=50000;                 
int PERIOD;
unsigned KEY,temp;
//副程式宣告
void TIMER1_initinal(int baudrate);
void delay (int j);
//主程式開始
void main(void)
{

 TIMER1_initinal(9600);               // 使用UART,baudrate=9600
 PERIOD=TIMES-PWMHIGH;
 TMOD = (TMOD & 0xF0) | 0x01;         // Set T/C0 Mode
 TH0= PERIOD/256;                     // load sampleing rate
 TL0= PERIOD%256;                     //
 ET0 = 1;                             // Enable Timer 0 Interrupts
 TR0 = 1;                             // Start Timer 0 Running
 EA = 1;                              // Global Interrupt Enable

 printf("\n7 KEY Detect Program\n\n");

 SCAN0=SCAN1=SCAN2=SCAN3=1;
 DET3=DET2=DET1=DET0=1;               // 設定成輸入pin
 n_SCAN=0;
 UP=DOWN=LEFT=RIGHT=0;

 while(1)
  {
   if((P2&0xFF)!=0xFF)                // 偵測是否按按鍵?
    {
     temp=P2&0xFF;                   // 第一次儲存按鍵值
      delay(6000);                    // 延遲 0.48us*6000=2.88ms,防彈跳調整
      KEY=P2&0xFF;                    // 第二次讀取按鍵值
      if (KEY&&temp)                  // 判別是否為同一鍵
      { 
       delay(6000);
       switch(KEY)                         
         {
          case 0x7B: printf("SW20 pressed, code=0x7B\n");
                    UP^=1;
                    break;
                    
          case 0x7D: printf("SW15 pressed, code=0x7D\n");
                    LEFT^=1;
                    break;
             
          case 0x7E: printf("SW19 pressed, code=0x7E\n");
                    UP=DOWN=LEFT=RIGHT=1;
                    break;
                                          
          case 0xBD: printf("SW14 pressed, code=0xBD\n");
                    DOWN^=1;
                    break;
                    
          case 0xBE: printf("SW18 pressed, code=0xBE\n");
                    DOWN^=!(UP^=1);                      // binary down counter
                     LEFT^=(!DOWN && !UP);
                     RIGHT^=(!LEFT && !DOWN && !UP);
                    break;
                               
          case 0xDE: printf("SW17 pressed, code=0xDE\n");
                    DOWN^=UP^=1;                         // binary up counter
                     LEFT^=(DOWN && UP);
                     RIGHT^=(LEFT && DOWN && UP);
                    break;
                    
          case 0xEE: printf("SW16 pressed, code=0xEE\n");
                    RIGHT^=1;
                    break;
                               
          default: break;                
         }
       //delay(6000); 
      }
    }
  }
}

//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
{
 if((SCAN0==1)&&(SCAN1&&SCAN2&&SCAN3)&&(n_SCAN==0))
  {
   TR0=0;
   SCAN0=0;
   PERIOD = TIMES-PWMLOW;
   TH0= PERIOD/256;
   TL0= PERIOD%256;
   TR0=1;
  }
 else if((SCAN0==0)&&(SCAN1&&SCAN2&&SCAN3)&&(n_SCAN==0))
   {
     TR0=0;
     n_SCAN=1;                                         // 準備掃瞄列1
     SCAN0=1;
     PERIOD = TIMES-PWMHIGH;                    
     TH0= PERIOD/256;
     TL0= PERIOD%256;
     TR0=1;
    }

  if((SCAN1==1)&&(SCAN0&&SCAN2&&SCAN3)&&(n_SCAN==1))
  {
   TR0=0;
   SCAN1=0;
   PERIOD = TIMES-PWMLOW;
   TH0= PERIOD/256;
   TL0= PERIOD%256;
   TR0=1;
  }
 else if((SCAN1==0)&&(SCAN0&&SCAN2&&SCAN3)&&(n_SCAN==1))
   {
     TR0=0;
     n_SCAN=2;                                         // 準備掃瞄列2
     SCAN1=1;
     PERIOD = TIMES-PWMHIGH;                    
     TH0= PERIOD/256;
     TL0= PERIOD%256;
     TR0=1;
    }
 if((SCAN2==1)&&(SCAN0&&SCAN1&&SCAN3)&&(n_SCAN==2))
  {
   TR0=0;
   SCAN2=0;
   PERIOD = TIMES-PWMLOW;
   TH0= PERIOD/256;
   TL0= PERIOD%256;
   TR0=1;
  }
 else if((SCAN2==0)&&(SCAN0&&SCAN1&&SCAN3)&&(n_SCAN==2))
   {
     TR0=0;
     n_SCAN=3;                                         // 準備掃瞄列3
     SCAN2=1;
     PERIOD = TIMES-PWMHIGH;                    
     TH0= PERIOD/256;
     TL0= PERIOD%256;
     TR0=1;
    }
if((SCAN3==1)&&(SCAN0&&SCAN1&&SCAN2)&&(n_SCAN==3))
  {
   TR0=0;
   SCAN3=0;
   PERIOD = TIMES-PWMLOW;
   TH0= PERIOD/256;
   TL0= PERIOD%256;
   TR0=1;
  }
 else if((SCAN3==0)&&(SCAN0&&SCAN1&&SCAN2)&&(n_SCAN==3))
   {
     TR0=0;
     n_SCAN=0;                                          // 準備掃瞄列0
     SCAN3=1;
     PERIOD = TIMES-PWMHIGH;                    
     TH0= PERIOD/256;
     TL0= PERIOD%256;
     TR0=1;
    }
                     
}

void delay (int j)
{
 while(j)
  j--;
}


//======== CONSOLE MESSAGE =======
7 KEY Detect Program
SW20 pressed, code=0x7B
SW14 pressed, code=0xBD
SW15 pressed, code=0x7D
SW16 pressed, code=0xEE
SW17 pressed, code=0xDE
SW18 pressed, code=0xBE
SW19 pressed, code=0x7E