久久久久久久999_99精品久久精品一区二区爱城_成人欧美一区二区三区在线播放_国产精品日本一区二区不卡视频_国产午夜视频_欧美精品在线观看免费

 找回密碼
 立即注冊

QQ登錄

只需一步,快速開始

搜索
查看: 2111|回復: 0
收起左側

藍僑杯單片機編程筆記

[復制鏈接]
ID:247772 發表于 2018-3-19 08:55 | 顯示全部樓層 |閱讀模式
藍僑杯單片機編程筆記

一、              IO口編程

二、              數碼管動態掃描和定時器

三、              矩陣鍵盤

四、              串口通訊和串口中斷

五、              外部中斷的使用

六、              實時時鐘DS1302的使用

七、              PCF8591與IIC總線的使用

八、              DS18B20溫度芯片的使用

九、              超聲波傳感器的使用

十、              步進電機與直流電機的使用

十一、              擴展:宏定義編程方法(推薦)

十二、              注意事項(常見編程錯誤)

  • IO口編程
IO編程,該開發板使用了573鎖存器,通過P2口的5,6,7位連接3-8譯碼器,擴展出了8個口,其中4個口分別連接4個573鎖存器,這里以LED的鎖存器來舉例:
原理圖573:
分析代碼:
P2=((P2&0x1f)|0x80);
其中0x1f=0001 1111,P2與0x1f進行與運算,高三位清零,其余位保持原來狀態,不改變,即把控制3-8譯碼器的高三位留出來:
接著再或上0x80;容易發現0x80=1000 0000;或運算,與1或結果為1,與0或結果不變,所以或上0x80只需看P2的高三位,則高三位為100,對應3-8譯碼器的話,P2^7=1;P2^6=0;P2^5=0;
所以輸出Y4=0;Y4再經過與非運算,看下圖示:
則輸出Y4C=1;即LED對應的鎖存器的片選信號被選中,鎖存器打通,接下來就可以對P0口進行操作,操作完之后,
P2=P2&0x1f;P2高三位直接清零,此時Y4C=0,則把鎖存器鎖上了。
類似的方法,數碼管、蜂鳴器等都是如此操作,
選中鎖存器代碼:
P2=((P2&0x1f)|(這里填對應鎖存器的位移號))。
  • 數碼管動態掃描和定時器
數碼管顯示分為段選和位選,
數碼管定義和顯示函數:
code unsigned char tab[] = { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unsigned char dspbuf[]={10,10,10,10,10,10,10,10};
unsigned char dspcom=0;
void display()
{
//段選,消隱
              P2=((P2&0x1f)|0xe0);
              P0=0xff;
              P2=P2&0x1f;
//位選
              P2=((P2&0x1f)|0xc0);
              P0=(1<<dspcom);
              P2=P2&0x1f;
//段碼輸入
              P2=((P2&0x1f)|0xe0);
              P0=tab[dspbuf[dspcom]];
              P2=P2&0x1f;
              if(++dspcom==8)
                            dspcom=0;
}注意:這里1左移dspcom位,剛開始dspcom=0,則1左移dspcom位依舊為1,接著dspcom每次自增1,1對應二進制0000 0001,即把1每次向左移,每次都比上一次多移一位,直至8位移完,對應8個數碼管。
定時器配置:
這里只需記住定時器的配置,知道怎么使用就可以了。首先有兩個定時器,T0和T1,(也有的單片機有T2),定時器有4種工作方式0,1,2,3;其中最常用的是方式1(16位),其次是方式2(8位自動重裝,串口通訊中斷會用到)。
定時器需要配置:TMOD |=0x01;配置成使用定時器0,工作方式為1;同理使用定時器1工作方式1:TMOD |=0x10;則同時使用兩個定時器且工作方式為1,那么可以:TMOD |=0x11;
定時器1配置成工作方式2:TMOD |=0x20;
接著配置(以定時器0舉例):
TH0=(65535-2000)/256;//配置初值
TL0=(65535-2000)%256;
ET0=1;
TR0=1;//定時0中斷
EA =1;//總中斷
定時器1也是同理的,只不過0要改成1.
接著定時中斷函數和優先級:
定時器0
void isr_timer_0(void) interrupt 1  //默認中斷優先級 1
{
    TH0 = (65536-2000)/256;
    TL0 = (65536-2000)%256;  //定時器重載
    display();
}
定時器1:
void isr_timer_1(void)  interrupt 3  //默認中斷優先級 3
{
    TH0 = (65536-2000)/256;
    TL0 = (65536-2000)%256;  //定時器重載
    display();
}
注意:定時器0優先級為1,定時器1為3,串口中斷優先級為4,總共有5個中斷源,后面還會介紹外部中斷和串口中斷。
數碼管動態掃描,顯示函數放在定時中斷函數里面,2ms掃一次是最穩定的!!
  • 矩陣鍵盤
矩陣鍵盤需要死記了!這里不再講獨立鍵盤。
第二種單片機鍵盤掃描代碼(沒有消抖):
sfr P4^4=0xC0;
//鍵盤定義
sbit r1=P3^0;  //4行
sbit r2=P3^1;
sbit r3=P3^2;
sbit r4=P3^3;
//4列
sbit c1=P4^4;
sbit c2=P4^2;
sbit c3=P3^5;
sbit c4=P3^4;
//讀取矩陣鍵盤鍵值
unsigned char key_scan()
{
              unsigned char key_value;
              r1=0;
              r2=r3=r4=1;
              c1=c2=c3=c4=1;
              if(!c1) key_value=0;
              else if(!c2) key_value=1;
              else if(!c3) key_value=2;
              else if(!c4) key_value=3;
    r2=0;
              r1=r3=r4=1;
              c1=c2=c3=c4=1;
              if(!c1) key_value=4;
              else if(!c2) key_value=5;
              else if(!c3) key_value=6;
              else if(!c4) key_value=7;
              r3=0;
              r2=r1=r4=1;
              c1=c2=c3=c4=1;
              if(!c1) key_value=8;
              else if(!c2) key_value=9;
              else if(!c3) key_value=10;
              else if(!c4) key_value=11;
              r4=0;
              r2=r3=r1=1;
              c1=c2=c3=c4=1;
              if(!c1) key_value=12;
              else if(!c2) key_value=13;
              else if(!c3) key_value=14;
              else if(!c4) key_value=15;
              return key_value;
}
  • 串口通訊和串口中斷
串口中斷配置只需記住幾個寄存器就行了,
初始化:
              SCON =0x50;  //串口配置成模式1
TMOD |=0x20;//定時器1,方式2,8位自動重裝
              TH1=256-(unsigbedchar)(SYSTEMCLOK/BAUDRATE/384+0.5);//定時初值
                            ES=1;                 //串口中斷打開
                            TR1=1;      //啟動定時器1
                            EA=1;                            //總中斷打開
這里必須使用定時器1,不能用定時器0.
下面是模塊化的函數:
void Uart_Init()
{
              SCON = 0x50;
              TMOD |=0x20;
              TH1=256-(SYSREMCLOCK/BAUDRATE/384+0.5);
              ES=1;
              TR1=1;
              EA=1;
}
void UartSend(unsigned char*pBuff,int length)
{
unsigned char c;
int i=0;
for(i=0;i<length;i++)
{
              c=pBuff[ i];
              SBUF=c;
              while(TI==0);
              TI=0;
}
}
接收數據可以這樣寫:
定義全局變量:
unsigned char uart_buf[100];//串口緩沖區
unsigned int  uart_Count=0;//串口數據長度
void uart_inte() interrupt 4
{
              unsigned char c;
              if(RI)
              {
                            RI=0;
                            c=SBUF;
                            uart_buf[uart_Count]=c;
                            uart_Count++;
              }                                                      
}
如果可以指定的接收,可以這樣寫
//串口中斷服務函數
void isr_uart(void) interrupt 4{
    if(RI){
        RI = 0;  //清除接收標志位
        rxbuf[rxcnt] = SBUF;
       if(rxbuf[rxcnt] == '\n'){
            rxcnt = 0;
            rx_over = 1;
            ES = 0;
//回車為接收結束標志,檢測到回車符后,關閉串口中斷
        }     
                            else{
                                          rxcnt++;
                            }
    }
}
當接收完一幀數據時關閉串口中斷,設一個標志位,處理完之后再打開。
#include "reg51.h"
#include "intrins.h"
typedef unsigned char BYTE;
typedef unsigned int WORD;
BYTE code_tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff};
char arry[10]="I CAN PLAY";
unsigned char x;
#define FOSC 11059200//12000000L          //系統頻率
#define BAUD 115200             //串口波特率
#define NONE_PARITY     0       //無校驗
#define ODD_PARITY      1       //奇校驗
#define EVEN_PARITY     2       //偶校驗
#define MARK_PARITY     3       //標記校驗
#define SPACE_PARITY    4       //空白校驗
#define PARITYBIT NONE_PARITY   //定義校驗位
sfr AUXR  = 0x8e;               //輔助寄存器
sfr P_SW1   = 0xA2;             //外設功能切換寄存器1
#define S1_S0 0x40              //P_SW1.6
#define S1_S1 0x80              //P_SW1.7
sbit P22 = P2^2;
bit busy;
void SendData(BYTE dat);
void SendString(char *s);
void main()
{
    ACC = P_SW1;
    ACC &= ~(S1_S0 | S1_S1);    //S1_S0=0 S1_S1=0
    P_SW1 = ACC;                //(P3.0/RxD, P3.1/TxD)
//  ACC = P_SW1;
//  ACC &= ~(S1_S0 | S1_S1);    //S1_S0=1 S1_S1=0
//  ACC |= S1_S0;               //(P3.6/RxD_2, P3.7/TxD_2)
//  P_SW1 = ACC;
//
//  ACC = P_SW1;
//  ACC &= ~(S1_S0 | S1_S1);    //S1_S0=0 S1_S1=1
//  ACC |= S1_S1;               //(P1.6/RxD_3, P1.7/TxD_3)
//  P_SW1 = ACC;
//#if (PARITYBIT == NONE_PARITY)
    SCON = 0x50;                //8位可變波特率
//#elif (PARITYBIT == ODD_PARITY) || (PARITYBIT == EVEN_PARITY) || (PARITYBIT == MARK_PARITY)
  //  SCON = 0xda;                //9位可變波特率,校驗位初始為1
//#elif (PARITYBIT == SPACE_PARITY)
//   SCON = 0xd2;                //9位可變波特率,校驗位初始為0
//#endif
    AUXR = 0x40;                //定時器1為1T模式
    TMOD = 0x20;                //定時器1為模式2(8位自動重載)
    TL1 = (256 - (FOSC/32/BAUD));   //設置波特率重裝值
    TH1 = (256 - (FOSC/32/BAUD));
    TR1 = 1;                    //定時器1開始工作
    ES = 1;                     //使能串口中斷
    EA = 1;
    while(1)
              {
//              SendString(arry);
              SendString("I CAN PLAY~~\r\n");//上位機顯示接收文本模式
//              SendData(x);
              }
}
/*----------------------------
UART 中斷服務程序
-----------------------------*/
void Uart() interrupt 4 using 1
{
    if (RI)//單片機接收數據,發送數字0~9,可在數碼管上顯示,發送hex模式
    {
        RI = 0;                 //清除RI位
//        P0 = SBUF;
                            x=SBUF;//將緩存器的數據賦值給x
                            P0=0xff;                //消隱
                            P2|=0xe0;
                            P2&=0x1f;
                           
                            P0=code_tab[x];                                          //段選
                            P2|=0xe0;
                            P2&=0x1f;
                           
                            P0=0x01;                                                        //位選第一位
                            P2|=0xc0;
                            P2&=0x3f;
    }
    if (TI)
    {
        TI = 0;                 //清除TI位
        busy = 0;               //清忙標志
    }
}
/*----------------------------
發送串口數據
----------------------------*/
void SendData(BYTE dat)
{
    while (busy);               //等待前面的數據發送完成
    ACC = dat;                  //獲取校驗位P (PSW.0)
    if (P)                      //根據P來設置校驗位
    {
#if (PARITYBIT == ODD_PARITY)
        TB8 = 0;                //設置校驗位為0
#elif (PARITYBIT == EVEN_PARITY)
        TB8 = 1;                //設置校驗位為1
#endif
    }
    else
    {
#if (PARITYBIT == ODD_PARITY)
        TB8 = 1;                //設置校驗位為1
#elif (PARITYBIT == EVEN_PARITY)
        TB8 = 0;                //設置校驗位為0
#endif
    }
    busy = 1;
    SBUF = ACC;                 //寫數據到UART數據寄存器
}
/*----------------------------
發送字符串
----------------------------*/
void SendString(char *s)
{
    while (*s)                  //檢測字符串結束標志
    {
        SendData(*s++);         //發送當前字符
    }
}
記不住可以看手冊!!
#include "reg51.h"
#include "intrins.h"
typedef unsigned char BYTE;
typedef unsigned int  WORD;
#define FOSC 11059200L
#define BAUD 115200
sfr AUXR=0x8e;                //輔助寄存器
sbit P22=P2^2;
bit busy;
void SendData(BYTE dat);
void SendString(char *s);
void main()
{
              SCON=0x50;
              AUXR=0x40;              //設置定時器T1為1T,即一個機器周期模式
              TMOD=0x20;
              TL1=(256-(FOSC/32/BAUD));
              TH1=(256-(FOSC/32/BAUD));
              TR1=1;
              ES=1;
              EA=1;
              SendString("Hello");
              while(1);
}
void Uart() interrupt 4 using 1
{
              if(RI)
              {
                            RI=0;
                            P0=SBUF;
              }
              if(TI)
              {
                            TI=0;
                            busy=0;
              }
}
void SendData(BYTE dat)
{
              while(busy);
              busy=1;
              SBUF=dat;
}
void SendString(char *s)
{
              while(*s)
              {
                            SendData(*s++);
              }
}
  • 外部中斷的使用
#include <reg52.h>
sbit L1=P0^0;
int main(){
              IT0=1; //IT0=1,下降沿觸發外部中斷0,IT0=0邊沿觸發
              EX0=1;//使用外部中斷0
              EA=1;
              while(1){
                            }
}
void Ex_int0() interrupt 0 //外部中斷優先級最高
{
P2=((P2&0x1f)|0x80);
              L1=~L1;
              P2=(P2&0x1f);
}            
其中,外部中斷的引腳控制是P3^2,P3^3,即對應獨立按鍵的S5,S4。
  • 實時時鐘DS1302的使用
藍橋杯提供函數,解釋為:
里面的命令和寫入的數據可以看芯片手冊:
左側的READ、WRITE分別是讀寫的命令,BIT7-BIT0是要寫入的數據,根據需要進行配置。DS1302只需記住這兩個函數即可:Write_Ds1302( , )與Read_Ds1302(x),配置看手冊。
重點:芯片表說明:第一行:秒->因為秒的范圍是0-59,所以6,5,4位表示秒的十位,3,2,1,0表示個位,十位最大是5,所以三位即可。
第二行:跟上面一樣;
第三行:7位:1為12小時制,0為24小時制;5位:12小時制時為0表示上午,1表示下午,24小時制時,和4位一起表示小時的十位;
其余的時間一樣的表示。
倒數第二行:只看7位:為1時禁止寫數據,所以開始寫數據時必須置0;
讀數時:
需要加“寫操作這一行代碼”。
讀的話直接按照命令讀即可。
DS1302進階(BCD碼轉換):解決之前60秒不能進位的問題。
  • 寫入初始值時,要把10十進制數轉換為BCD碼,
例:寫入時間->17:58:50
Ds1302_Single_Byte_Write(0x8e, 0x00);//寫操作
              Ds1302_Single_Byte_Write(0x85, ((17/10)<<4 | (17%10)));//寫時
    Ds1302_Single_Byte_Write(0x83, ((58/10)<<4 | (58%10)));//寫分
              Ds1302_Single_Byte_Write(0x81, ((50/10)<<4 | (50%10)));//寫秒
              Ds1302_Single_Byte_Write(0x8e, 0x80);//寫保護
即轉換的公式是:((Value/10)<<4 | (Value%10)),可以寫一個settime()函數。
2 ) 讀數讀回來的數要進行轉換成十進制數
((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
八進制轉十進制->
ReadValue=Ds1302_Single_Byte_Read(0x85);
                            hour=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
              !!(這句一定不要省)              Ds1302_Single_Byte_Write(0x00, 0x00);//寫操作
                            ReadValue=Ds1302_Single_Byte_Read(0x83);
                            minute=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
                            Ds1302_Single_Byte_Write(0x00, 0x00);//寫操作
                            ReadValue=Ds1302_Single_Byte_Read(0x81);
                            sec=((ReadValue&0x70)>>4)*10 + (ReadValue&0x0F);
                            Ds1302_Single_Byte_Write(0x00, 0x00);//寫操作
顯示:
                            dspbuf[0]=hour/10;
                            dspbuf[1]=hour%10;
                            dspbuf[2]=minute/10;
                 dspbuf[3]=minute%10;
                            dspbuf[4]=sec/10;
                            dspbuf[5]=sec%10;
  • PCF8591IIC總線的使用
  • IIC總線的使用:
比賽提供了IIC的兩個庫文件,IIC.h;IIC.c,其中需要注意的函數是:
其中,該函數是初始化的,當使用AD轉換的時候需要在main函數開始時調用,該函數內部只需看這句代碼即可:i2c_sendbyte(0x03);//ADC通道3,板上有4個模擬輸入口,分別為0,1,2,3;設置哪一個模擬輸入口就是根據這句代碼,0x03表示通道3,這是根據芯片手冊配置的,如圖:
8位前6位不用管,都為0,最后兩位就是配置選擇哪一個通道的。
第二個函數:
讀取AD轉換后的數值,這個函數直接調用就可以了,函數內部如何實現不用管,但是需要注意的是:該函數掃描調用最好是100ms。
第三個函數,上面的都是AD轉換,即模擬信號轉數字信號,下面這個函數是DA轉換,數字信號轉換成模擬信號,就是單片機輸出數字信號,用萬能表去量單片機引出的引腳,量一下電壓大小,這個估計比賽不會考,不過預防萬一:
該函數和上面兩個函數分離開來的,一、二函數是要在一起使用,初始化后之后才能調用,第三個加入頭文件,直接調用即可,比較簡單!!
上面說法有誤,A/D轉換的初始化函數和讀取轉換后的數值都需要自己寫。
這里了解一下PCF8591只需根據時序格式發送地址字節和控制字節:,這是地址字節,其中A2,A1,A0硬件已經接地,故都為0,最低位表示的是你要從IIC總線上讀數還是寫數據,1表示讀,0表示寫,即讀數據發的地址是:0x91;寫數據發的地址是0x90;
控制字節:
由芯片資料知,控制字節有8位,有兩位固定是0,除了第0、1位需要自己設置,其他的我們都設為0,那些位都是一些具體的功能,我們暫時用不著,不用管先,第0、1位是模擬通道選擇,PCF8591上提供了4路模擬通道,根據需求進行選擇,如選擇通道3即發送控制字節:0x03;
地址字節和控制字節都明白了,接下來根據時序要求進行配置,A/D轉換需要一個初始化函數:Init_ADpcf8591();和一個獲得AD轉換后的數值的函數:adc_pcf8591(); 其中初始化函數的作用是發送AD轉換的控制字節;adc_pcf8591()發送讀取得地址并讀回數據,先寫指令才能讀;格式如下:
這個是初始化的協議:分別是startIIC、(地址寫)發送0x90、等待應答、發送控制字節(AD這里是選擇通道的指令,如選擇通道3,0x03)0x03、等待應答、(達到目的,沒有后續的操作,直接停止總線)StopIIC.
初始化的函數就是如此寫;
adc_pcf8591的協議:
依次是:startIIc、發送讀地址0x91、等待應答、讀回AD轉換后的數值、讀回后發送應答給PCF8591,表示收到,并且不需要再返回應答,要傳參數1,如圖紅圈示,即函數Ack(1);、最后stopIIC總線。
D/A轉換(其實挺麻煩,先前太自信了,哈):
所謂D/A轉換其實就是把數字信號轉換成模擬信號輸出,用單片機發數字通過D/A轉換成電壓輸出,檢測的方法可以用電壓表測量。
配置的方法跟A/D類似,先發地址字節,再發控制字節,然后把數字發出去(AD這里是接收模擬信號,是相反的機制)。
控制字節:
如圖示,控制字節的第6位是1的話是模擬輸出模式,其余位全為0,發送格式跟AD一樣:
代碼如一開始圖示。
  • EEPROM的使用,AT24C02,可以掉電依舊保存上一次操作的數據,下次上電后接著運行。
需要注意兩個函數,一個是寫進EEPROM里面保存,再次上電再從里面讀回來:
其中寫函數需要指定AT24C02的地址以及需要寫入的數據,讀函數要想取回寫進的數據,需要從相同的地址里面讀:
其中AT24C02的存儲地址是0x00,可以是其他地址,如0x02,但是讀和寫的地址必須一致。
寫與讀的協議與AD或DA相同,
由芯片資料及原理圖知EEPROM(AT24C02)的寫地址為0xa0;讀地址為0xa1;注意:讀數的時候讀出一個數之后發送一個應答信號,若ACK(0)表示還想繼續讀下一個字節,若ACK(1);則不想再讀數,讓EEPROM停止發送。
  • DS18B20時鐘芯片的使用
比賽有提供代碼,只需記住這個函數:
讀取溫度值,整數(其中,提示EA總中斷要打開、關閉,也可以不用)。
浮點數的表示。
注意,只有提供函數,沒有提供讀取溫度的函數,即上面的那個,只有下面:這幾個函數。
編寫讀取溫度的函數需要記住DS13B20的三條指令,0xCC,跳過ROM檢測;然后啟動溫度轉換:0x44;轉換需要時間,這里精確延時Delay_OneWire(200);然后再次初始化,再次執行跳過,然后讀取溫度指令:0xBE.;注意讀出的溫度是低字節先,然后才是高字節,分別用兩個變量保存還要通過公式轉換成我們需要的整數或浮點數。完整代碼如上圖示。
  • 超聲波傳感器的使用
#include "reg52.h"  //定義51單片機特殊功能寄存器
#include "intrins.h"
#include "absacc.h"
//12M用這個
/*#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();
                 _nop_();_nop_();_nop_();_nop_(); _nop_();}*/
//11.0592用這個
#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();
                 _nop_();_nop_();}
sbit TX = P1^0;  //發射引腳
sbit RX = P1^1;  //接收引腳
code unsigned char tab[] = { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,\
                             0xff};
unsigned char dspbuf[8] = {10,10,10,10,10,10,10,10};  //顯示緩沖區
unsigned char dspcom = 0;
unsigned int intr = 0;
bit s_flag;
unsigned int t = 0;
void send_wave(void);
void display(void);
void main(void)
{
    unsigned int distance;
    TMOD |= 0x11;  //配置定時器工作模式
    TH0 = (65536-2000)/256;
    TL0 = (65536-2000)%256;
    TH1 = 0;
    TL1 = 0;
    EA = 1;
    ET0 = 1;  //打開定時器0中斷
    TR0 = 1;  //啟動定時器  
    while(1){
        /** 200毫秒更新一次數據 */
                            if(s_flag)
        {
            s_flag = 0;
            /** 關閉定時器0中斷:計算超聲波發送到返回的時間
            send_wave();  //發送方波信號
            TR1 = 1;  //啟動計時
                                          while((RX == 1) && (TF1 == 0));  //等待收到脈沖
                                          TR1 = 0;  //關閉計時
                                          //發生溢出
                                          if(TF1 == 1)
                                          {
                                                        TF1 = 0;
                                                        distance = 9999;  //無返回
                                          }
                                          else
                                          {
                                                        /**  計算時間  */
                                                        t = TH1;
                                                        t <<= 8;
                                                        t |= TL1;
                                                        distance = (unsigned int)(t*0.017);  //計算距離                                                      
                                          }
                                          TH1 = 0;
                                          TL1 = 0;
        }
                            /** 數據處理                      */
                            dspbuf[5] = distance/100;
                            dspbuf[6] = distance%100/10;
                            dspbuf[7] = distance%10;      
    }
}
//定時器0中斷服務函數
void isr_timer_0(void)  interrupt 1  //默認中斷優先級 1
{
    TH0 = (65536-2000)/256;
    TL0 = (65536-2000)%256;  //定時器重載
              display();  //2ms執行一次
              if(++intr == 200){
        s_flag = 1;
        intr = 0;
    }
}
//顯示函數
void display(void){
              XBYTE[0xE000] = 0xff;  //去除鬼影
              XBYTE[0xC000] = (1<<dspcom);
              XBYTE[0xE000] = tab[dspbuf[dspcom]];
            
              if(++dspcom == 8){
                            dspcom = 0;
              }            
}
//TX引腳發送40KHz方波信號驅動超聲波發送探頭
void send_wave(void)
{
              unsigned char i = 8;  //發送8個脈沖
              do
              {
                            TX = 1;
                            somenop;
                            TX = 0;
                            somenop;
              }
              while(i--);
}
必要時還可以加個看門狗:              WDT_CONTR=0x34;
  • 步進電機與直流電機的使用
參考代碼如下:
#include <reg52.h>
sbit A1=P1^4; //定義步進電機連接端口
sbit B1=P1^3;
sbit C1=P1^2;
sbit D1=P1^1;
void qudong1();
#define Dy_A1 {A1=1;B1=0;C1=0;D1=0;}//A相通電,其他相斷電
#define Dy_B1 {A1=0;B1=1;C1=0;D1=0;}//B相通電,其他相斷電
#define Dy_C1 {A1=0;B1=0;C1=1;D1=0;}//C相通電,其他相斷電
#define Dy_D1 {A1=0;B1=0;C1=0;D1=1;}//D相通電,其他相斷電                 //采用1相勵磁
#define Dy_OFF {A1=0;B1=0;C1=0;D1=0;}//全部斷電
unsigned char Speed,Speed1;
/*------------------------------------------------
uS延時函數,含有輸入參數 unsigned char t,無返回值
unsigned char 是定義無符號字符變量,其值的范圍是
0~255 這里使用晶振12M,精確延時請使用匯編,大致延時
長度如下 T=tx2+5 uS
------------------------------------------------*/
void DelayUs2x(unsigned char t)
{  
while(--t);
}
/*------------------------------------------------
mS延時函數,含有輸入參數 unsigned char t,無返回值
unsigned char 是定義無符號字符變量,其值的范圍是
0~255
------------------------------------------------*/
void DelayMs(unsigned char t)
{
while(t--)
{
     //大致延時1mS
     DelayUs2x(245);
              DelayUs2x(245);
}
}
/*------------------------------------------------
                    主函數
------------------------------------------------*/
main()
{
Dy_OFF;
for(;;)
{
   qudong1();
  }
}
void qudong1()
{
unsigned int i=470;//旋轉一周時間
  Speed=5;
  while(i--)  //正向
  {        
     Dy_A1               
//遇到Coil_A1  用{A1=1;B1=0;C1=0;D1=0;}代替
     DelayMs(Speed);        
//改變這個參數可以調整電機轉速 ,
                             //數字越小,轉速越大,力矩越小
     Dy_B1                                                                      //順序從A1--D1相通電如果為正轉,那么順序從D1--A1相通電則為反轉
     DelayMs(Speed);
     Dy_C1
     DelayMs(Speed);
     Dy_D1
     DelayMs(Speed);
  }
Dy_OFF
  i=512;
  while(i--)//反向
  {
     Dy_D1                //遇到Coil_A1  用{A1=1;B1=0;C1=0;D1=0;}代替
     DelayMs(Speed);         //改變這個參數可以調整電機轉速 ,
                                       //數字越小,轉速越大,力矩越小
     Dy_C1
     DelayMs(Speed);
     Dy_B1
     DelayMs(Speed);
     Dy_A1
     DelayMs(Speed);
  }                 
}
直流電機:
#include<reg52.h>
#define uint unsigned int
void drive();
void delay(uint);
sbit dj1=P1^0; //電機,1引腳
uint set; //set為電機轉角標志位
unsigned char angle,angle1;              //angle為電機PWM變化打角
void Time0_Init()              //中斷初始化
{
TMOD=0X01;
IE=0X82;
TH0=(65536-58)/256;                           
TL0=(65536-58)%256;
TR0=1;
}
void main()                            //主函數
{
set=0;
angle=62;  // 改變angle的值可以改變電機的占空比
Time0_Init();
  for(;;)
   {
    }               
}
void T0_time()interrupt 1
{
TH0=(65536-58)/256;                           
TL0=(65536-58)%256;
  if(set<angle)
   dj1=1;
else
  dj1=0;
set++;
if(set>165) set=0;   //電機占空比
}
  • 擴展:宏定義編程方法(推薦)
常用的可以宏定義,省時,下面以數碼管為例:
              #define rst573 P2&=0x1f
#define Y6C P2=              ((P2&0x1f)|0xc0)
#define Y7C P2=              ((P2&0x1f)|0xe0)
code unsigned char tab[] = { 0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unsigned char dspbuf[8] = {10,10,10,10,10,10,10,10};  //顯示緩沖區
unsigned char dspcom;
unsigned char flag;
void display()
{
              Y7C;
              P0=0xff;
              rst573;
              Y6C;
              P0=1<<dspcom;
              rst573;
              Y7C;
              P0=tab[dspbuf[dspcom]];
              rst573;
              if(++dspcom==8)
                            dspcom=0;
}
  • 注意事項(常見編程錯誤)
  • 設置標志位flag,常在定時的時候使用,一般我們常用的數據類型是unsigned char類型,有時候我們這樣判斷if(flag==500){flag=0; };這是十分明顯的錯誤,unsigned char8位,范圍是0-255,500已經超出其最大值的范圍了,但是編譯的時候是不會報錯的,我們可以設成unsigned int 類型,16位,范圍很大。
  • 模擬題中led閃爍的頻率隨著溫度值value與設定的范圍值比較而改變,這里困擾了我很久,終于在前人的代碼中找到解決方法了,這樣:設置的標志位flag不要直接在while循環里直接如:if(flag==100){flag=0;}不要這樣寫。應該在定時中斷新定義一個變量,如為標志位flag_100ms(假設進入一次定時中斷2ms):
void time0() interrupt 1
{ unsigned int i;
if(++i==50)
{  i=0;
flag_100ms=1;
}  
}
然后在需要用到的位置判斷標志位是否為1即可。
注意:也可以設靜態變量,建議用:
void time0() interrupt 1
{
    TH0=(65535-2000)/256;
              TL0=(65535-2000)%256;
              static unsigned int i=0;
              static unsigned int j=0;
              if(++i==100)
              {                                         
                            i=0;
                  flag_200ms=1;            
              }
              if(++j==200)
              {
                            j=0;
                            flag_400ms=1;
              }            
}
3、注意DS18b20溫度傳感器,因為使用的單片機芯片不一樣,晶振頻率不一樣,而DS18b20對時序的要求又很嚴格,所以這里記住兩種單片機的延時程序://單總線延時函數
#ifndef STC12
void Delay_OneWire(unsigned int t)  //STC89C52RC
{
              while(t--);
}
#else
void Delay_OneWire(unsigned int t)  //STC12C5260S2
{
              unsigned char i;
              while(t--){
                            for(i=0;i<12;i++);
              }
}
#endif
4、使用串口通訊傳一個數組給PC機,如果是文本模式顯示字符,需要將字符的ASII碼轉換成文本字符,還需在數組末尾加一個結束符‘\0’:
Val[0]='{';
              Val[1]=(hour/10)+48;
   。
              。
              。
              Val[19]='H';
              Val[20]='}';
              Val[21]='\0';
5、串口通訊波特率設置及初始化函數:
sfr AUXR=0x8e;
//宏定義區
#define BAUD 1200//波特率;需要設置哪個波特率只需在這里更改即可
#define FOSC 11059200L //晶振頻率
void InitSerial()
{
              SCON=0x50;
              TMOD |=0x00;//使用16位自動重載方式,選擇T1
              AUXR=0x40;//設置定時器為一個周期,即1T
              TL1=(65536-(FOSC/4/BAUD));
              TH1=(65536-(FOSC/4/BAUD))>>8;
              TR1=1;
              ES=1;
}
6、串口中斷函數及發送、結束函數:
void Uart() interrupt 4 using 1
{
              if(RI){
                            RI=0;
                            value=SBUF;
              }
              if(TI){
                            TI=0;
                            busy=0;
              }
}
void SendData(unsigned char dat)
{
              while(busy);
              busy=1;
              SBUF=dat;
}
void SendString(unsigned char *s)
{
              while(*s){
                            SendData(*s++);
              }
}
7、簡單的電路設計知識點:
SOURCE CURRENT 電流源
SOURCE VOLTAGE 電壓源
定值無極性電容;CAP
定值有極性電容;CAP
繼電器:RELAY. LIB
運放:OPAMP
BATTERY 直流電源
DIODE 二極管
DIODE SCHOTTKY 穩壓二極管
NPN NPN三極管
NAND 與非門
NOR 或非門
NOT 非門
4013 D 觸發器
4027 JK 觸發器

8、LED閃爍控制程序參考:
              static unsigned char LED=0xfe;
              XBYTE[0x8000]=LED=LED^0x01;(和0x01進行異或運算,L1閃爍!!)
9、數碼管的碼值(牢記):
tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xff,0xbf};

完整的Word格式文檔51黑下載地址:
藍僑杯單片機編程筆記新.docx (976.4 KB, 下載次數: 9)


回復

使用道具 舉報

您需要登錄后才可以回帖 登錄 | 立即注冊

本版積分規則

小黑屋|51黑電子論壇 |51黑電子論壇6群 QQ 管理員QQ:125739409;技術交流QQ群281945664

Powered by 單片機教程網

快速回復 返回頂部 返回列表
主站蜘蛛池模板: 蜜桃视频在线观看免费视频网站www | 欧美999| 欧美一级特黄aaa大片在线观看 | 全部免费毛片在线播放网站 | 国产视频久久久 | 欧美一区二区在线观看 | 日韩精品成人免费观看视频 | 欧美精品一区二区三区视频 | 亚洲精品久久久久中文字幕欢迎你 | 国产成人网 | 男人的天堂亚洲 | 久久中文字幕一区 | 欧美在线一区二区三区 | av香港经典三级级 在线 | 国产精品美女久久久久久免费 | 亚洲欧美一区二区三区国产精品 | 欧美亚洲视频 | 狠狠爱免费视频 | 在线看亚洲 | 成人不卡一区二区 | 免费xxxx大片国产在线 | 国产一级片在线观看视频 | 中文字幕av网站 | 日韩一区二区在线播放 | 动漫www.被爆羞羞av44 | 久久国产美女视频 | 国产一级片精品 | 国产99久久精品一区二区300 | 9久久| 精品动漫一区 | 一区二区三区av夏目彩春 | 国产香蕉视频在线播放 | 欧洲性生活视频 | 羞羞视频网站在线观看 | 国产免费又黄又爽又刺激蜜月al | 久久综合一区二区三区 | 麻豆毛片 | 成人精品毛片国产亚洲av十九禁 | 免费观看的黄色网址 | 国产精品毛片一区二区三区 | 毛片a级毛片免费播放100 |