|
希望能得到學(xué)習(xí)與交流,大家有什么意見可以一起交流,含有我做的幾個(gè)項(xiàng)目的完整原理圖與單片機(jī)源碼.
單片機(jī)源程序如下:
- //******小車程序******
- #include"stc12c5a.h"
- #include <intrins.h>
- #define uchar unsigned char
- #define uint unsigned int
- uchar sys_mod = 't';//'t':循跡模式, 'r':遙控模式, 'l',激光引導(dǎo)模式
- //*******NRF24L01******
- uchar idata RxBuf[16]; //接收緩存 data區(qū)滿 存入idata區(qū)
- uchar idata TxBuf[16]; //發(fā)送緩存
- //******0:系統(tǒng)模式-- ‘t’:循跡模式,‘r’:遙控模式,'l':激光模式
- //******1: 時(shí)間高8位
- //******2: 時(shí)間低8位
- //******3: ADC4
- //******4: ADC5
- //******5: 感光板上最小電壓值
- //******6: 感光板上激光打到的位置
- //******7: 行駛步驟高8位
- //******8: 行駛步驟低8位
- //******9: 硬幣數(shù)量
- //*****10: 激光模塊上步進(jìn)電機(jī)轉(zhuǎn)過的角度高8位
- //*****11: 激光模塊上步進(jìn)電機(jī)轉(zhuǎn)過的角度低8位
- //*****12: addone變量 NRF24L01每發(fā)送一次數(shù)據(jù),addone自加1,接收方判斷發(fā)送方是否離線的一個(gè)標(biāo)志
- //addone在一定時(shí)間內(nèi)都保持不變說明發(fā)送方離線
- //*****13:未定義
- #define LED P36 //led燈接P3.6
- #define SPK P37 //蜂鳴器接P3.7
- //*********** LCD ************
- #define RS P44
- #define RW P45
- #define LCDEN P46
- #define LCD_DATA P0 //P0口接LCD數(shù)據(jù)口
- #define LCD_BUSY P07 //lcd1602忙碌標(biāo)志位
- uchar idata lcd_code[10];//用來標(biāo)記lcd1602 什么時(shí)候清顯示 每個(gè)頁面都設(shè)一個(gè)code,code不想同時(shí)清顯示
-
- //********** 紅外探頭及行進(jìn)方式宏定義 ***************
- #define PROBE_L P22 //左側(cè)紅外探頭 白色區(qū)域低電平 黑色高電平
- #define PROBE_M P21 //中間紅外探頭
- #define PROBE_R P20 //右側(cè)紅外探頭
- #define LEFT_Z P30 //左輪正極
- #define LEFT_F P31 //左輪負(fù)極
- #define RIGHT_Z P34 //右輪正極
- #define RIGHT_F P35 //右輪負(fù)極
- #define LEFT_GO { LEFT_Z = 1;LEFT_F = 0;} //左輪向前轉(zhuǎn)
- #define LEFT_BACK { LEFT_Z = 0;LEFT_F = 1;} //左輪向后轉(zhuǎn)
- #define LEFT_STOP { LEFT_Z = 0;LEFT_F = 0;} //左輪停止
- #define RIGHT_GO { RIGHT_Z = 1;RIGHT_F = 0;} //右輪向前轉(zhuǎn)
- #define RIGHT_BACK { RIGHT_Z = 0;RIGHT_F = 1;} //右輪向后轉(zhuǎn)
- #define RIGHT_STOP { RIGHT_Z = 0;RIGHT_F = 0;} //右輪停止
- //****************************************************************
- //uchar left_mod[5] = "STOP"; //左輪轉(zhuǎn)動(dòng)方式 用于在lcd上顯示
- //uchar right_mod[5] = "STOP"; //右輪轉(zhuǎn)動(dòng)方式 用于在lcd上顯示
- uchar probe_before = 's'; //上一次探頭的狀態(tài) 's':停止 'l':左轉(zhuǎn) 'g':前進(jìn) 'r':右轉(zhuǎn)
- uchar step = 1; //第?步 0表示檢測(cè)到硬幣
- uchar num_coin = 0; //硬幣數(shù)量
- uchar see_coin = 0; //0:未檢測(cè)到硬幣 1:檢測(cè)到硬幣
- uchar flag_see_coin = 0; //0:剛檢測(cè)到硬幣 1:不是剛檢測(cè)到 剛檢測(cè)到硬幣要為t1_flag_see_coin 置零
- uchar change_line = 1; //進(jìn)入內(nèi)圈的步驟
- uchar times_probe_l = 0; //左探頭探測(cè)到黑帶的次數(shù)
- uchar times_probe_r = 0; //右探頭探測(cè)到黑帶的次數(shù)
- uchar change_line_mod = '?';//進(jìn)入內(nèi)圈的方式 是左轉(zhuǎn)還是右轉(zhuǎn)
- #define xs 8 //系數(shù),1表示占空比再乘以0.1,設(shè)置合適 <=8 可安全使用12V的電池
- //**************** ADC *********************
-
- uchar idata adc5[49]; //data區(qū)滿 存到idata
- uchar times_adc = 0; //adc轉(zhuǎn)換完成的次數(shù)
- uchar num_vmin = 0; //電壓最小的光敏電阻的編號(hào) 0~48(橫向加1 縱向加7)
- uchar num_vmin_before = 24; //激光脫離前打到的點(diǎn) 第3行 第3列為停止的點(diǎn)
- uint volt = 0;
- //*********** CD4051通道 *********
- #define SW_CH P23 //行掃描a b c (選通行接地)
- #define SW_BH P24
- #define SW_AH P25
- #define SW_CL P26 //列掃描a b c (選通列輸出電壓值給ADC)
- #define SW_BL P27
- #define SW_AL P32
- //***************************************
- uint angle = 0; //步進(jìn)電機(jī)轉(zhuǎn)過的角度
- //******************* 定時(shí)器變量 ***********************
- uint t0_flag = 0; //定時(shí)器0進(jìn)入中斷的次數(shù)
- uint t1_flag = 0; //定時(shí)器1進(jìn)入中斷的次數(shù)
- uint t1_flag_add = 0; //為addone = addone_b 定時(shí),即為與發(fā)送端失聯(lián)時(shí)間定時(shí)
- uint t1_flag_time = 0; //系統(tǒng)時(shí)間中斷次數(shù) 1000次為1s
- uint t1_flag_see_coin = 0; //用于在檢測(cè)到硬幣時(shí) 停車2秒 和聲光報(bào)警功能
- uint t1_flag_laserout = 0; //為激光脫離感光板定時(shí)
- uchar flag_laserout = 0; //標(biāo)記是否剛脫離 0:剛脫離,1:已經(jīng)脫離 剛脫離置零t1_flag_laserout
- uchar t0_h;
- uchar t0_l;
- uchar t1_h;
- uchar t1_l;
- uint time_of_move = 0; //小車移動(dòng)總時(shí)間 單位s
- //*****************************************延時(shí)函數(shù)***************************************
- void delayms(uint ms)//延時(shí)?個(gè) ms
- {
- unsigned char a,b;
- while(ms--)
- {
- for(b=64;b>0;b--) // 僅作為粗略延時(shí) 中斷繁忙時(shí)差距很大
- for(a=45;a>0;a--);
- }
- }
- void delayus(uint us)
- {
- for(;us >0;us--)
- {
- _nop_();_nop_();_nop_();_nop_();_nop_();_nop_();
- _nop_();_nop_();_nop_();_nop_();_nop_();_nop_(); //stc12c5a不分頻 12MHz 下12個(gè)指令周期為1us
- }
- }
- //**********字符串復(fù)制函數(shù)**********
- void string_copy(uchar *target,uchar *source)//字符串復(fù)制 target:目標(biāo) source:源
- {
- uchar i = 0;
- for(i = 0;source[i] != '\0';i++)//注意target的長度 無保護(hù)措施!
- {
- target[i] = source[i];
- }
- target[i] = '\0';
- }
- //**********字符串比較函數(shù)**********
- uchar string_cmp(uchar *target,uchar *source)//字符串比較 target:目標(biāo) source:源
- {
- uchar revalue;
- uchar i = 0;
- for(i = 0;target[i] != '\0' && source[i] != '\0';i++) //兩個(gè)都不等于'\0'才執(zhí)行 出現(xiàn)一個(gè)等于'\0'就跳出
- {
- if(target[i] == source[i])
- {
- revalue = 1;
- }
- else
- {
- revalue = 0;
- break;
- }
- }
- if(revalue == 1)
- {
- if(target[i] == '\0' && source[i] == '\0')
- revalue = 1;
- else
- revalue = 0;
- }
- return(revalue);
- }
- //****************************************NRF24L01 IO端口定義*********************************
- #define CE P10
- #define SCK P11
- #define MISO P12
- #define CSN P16
- #define MOSI P17
- //#define IRQ P32 //以下程序IRQ不顯示中中斷
- //*****************************NRF24L01的接收和發(fā)送地址***************************************
- #define TX_ADR_WIDTH 5 // 5個(gè)字節(jié)的TX地址長度
- #define RX_ADR_WIDTH 5 // 5個(gè)字節(jié)的RX地址長度
- #define TX_PLOAD_WIDTH 16 // ?個(gè)字節(jié)的TX數(shù)據(jù)長度
- #define RX_PLOAD_WIDTH 16 // ?個(gè)字節(jié)的RX數(shù)據(jù)長度
- uchar const TX_ADDRESS[TX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01}; //本地地址
- uchar const RX_ADDRESS[RX_ADR_WIDTH]= {0x34,0x43,0x10,0x10,0x01}; //接收地址
- //***************************************NRF24L01寄存器指令**********************************
- #define READ_REG 0x00 // 讀寄存器
- #define WRITE_REG 0x20 // 寫寄存器
- #define RD_RX_PLOAD 0x61 // 讀取接收數(shù)據(jù)
- #define WR_TX_PLOAD 0xA0 // 寫待發(fā)數(shù)據(jù)
- #define FLUSH_TX 0xE1 // 沖洗發(fā)送 FIFO
- #define FLUSH_RX 0xE2 // 沖洗接收 FIFO
- #define REUSE_TX_PL 0xE3 // 定義重復(fù)裝載數(shù)據(jù)
- #define NOP 0xFF // 保留
- //*************************************SPI(nRF24L01)寄存器地址*****************************
- #define CONFIG 0x00 // 配置收發(fā)狀態(tài),CRC校驗(yàn)?zāi)J揭约笆瞻l(fā)狀態(tài)響應(yīng)方式
- #define EN_AA 0x01 // 自動(dòng)應(yīng)答功能設(shè)置
- #define EN_RXADDR 0x02 // 可用信道設(shè)置
- #define SETUP_AW 0x03 // 收發(fā)地址寬度設(shè)置
- #define SETUP_RETR 0x04 // 自動(dòng)重發(fā)功能設(shè)置
- #define RF_CH 0x05 // 工作頻率設(shè)置
- #define RF_SETUP 0x06 // 發(fā)射速率、功耗功能設(shè)置
- #define STATUS 0x07 // 狀態(tài)寄存器
- #define OBSERVE_TX 0x08 // 發(fā)送監(jiān)測(cè)功能
- #define CD 0x09 // 地址檢測(cè)
- #define RX_ADDR_P0 0x0A // 頻道0接收數(shù)據(jù)地址
- #define RX_ADDR_P1 0x0B // 頻道1接收數(shù)據(jù)地址
- #define RX_ADDR_P2 0x0C // 頻道2接收數(shù)據(jù)地址
- #define RX_ADDR_P3 0x0D // 頻道3接收數(shù)據(jù)地址
- #define RX_ADDR_P4 0x0E // 頻道4接收數(shù)據(jù)地址
- #define RX_ADDR_P5 0x0F // 頻道5接收數(shù)據(jù)地址
- #define TX_ADDR 0x10 // 發(fā)送地址寄存器
- #define RX_PW_P0 0x11 // 接收頻道0接收數(shù)據(jù)長度
- #define RX_PW_P1 0x12 // 接收頻道0接收數(shù)據(jù)長度
- #define RX_PW_P2 0x13 // 接收頻道0接收數(shù)據(jù)長度
- #define RX_PW_P3 0x14 // 接收頻道0接收數(shù)據(jù)長度
- #define RX_PW_P4 0x15 // 接收頻道0接收數(shù)據(jù)長度
- #define RX_PW_P5 0x16 // 接收頻道0接收數(shù)據(jù)長度
- #define FIFO_STATUS 0x17 // FIFO棧入棧出狀態(tài)寄存器設(shè)置
- uchar SPI_RW_Reg(uchar reg, uchar value);
- uchar SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars);
- //****************************************狀態(tài)標(biāo)志****************************************
- uchar bdata sta;
- sbit RX_DR =sta^6;
- sbit TX_DS =sta^5;
- sbit MAX_RT =sta^4;
- //********************************NRF24L01初始化******************************************
- void init_NRF24L01()
- {
- delayus(100);
- CE=0; // 片選使能
- CSN=1; // SPI使能
- SCK=0; // SPI時(shí)鐘拉低
- SPI_Write_Buf(WRITE_REG + TX_ADDR, TX_ADDRESS, TX_ADR_WIDTH); //寫本地地址
- SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, RX_ADDRESS, RX_ADR_WIDTH); //寫接收端地址
- SPI_RW_Reg(WRITE_REG + EN_AA, 0x01); //通道0自動(dòng)應(yīng)答
- SPI_RW_Reg(WRITE_REG + EN_RXADDR, 0x01); //允許接收地址頻道0
- SPI_RW_Reg(WRITE_REG + RF_CH, 0x32); //設(shè)置信道工作頻率,收發(fā)必須一致
- SPI_RW_Reg(WRITE_REG + RX_PW_P0, RX_PLOAD_WIDTH); //設(shè)置接收數(shù)據(jù)長度
- SPI_RW_Reg(WRITE_REG + RF_SETUP, 0x0f); //設(shè)置發(fā)射速率為2MHZ,發(fā)射功率為最大值0dB
- SPI_RW_Reg(WRITE_REG + CONFIG, 0x7c); //IRQ引腳不顯示中斷 掉電模式 1~16位CRC校驗(yàn)
- }
- //****************************************************************************************************
- //*函數(shù):uint SPI_RW(uint uchar)
- //*功能:NRF24L01的SPI寫時(shí)序
- //****************************************************************************************************
- uchar SPI_RW(uchar num)
- {
- uchar bit_ctr;
- for(bit_ctr=0;bit_ctr<8;bit_ctr++) // output 8-bit
- {
- MOSI = (num & 0x80); // output 'uchar', MSB to MOSI
- num = (num << 1); // shift next bit into MSB..
- SCK = 1; // Set SCK high..
- num |= MISO; // capture current MISO bit
- SCK = 0; // ..then set SCK low again
- }
- return(num); // return read uchar
- }
- //****************************************************************************************************
- //函數(shù):uchar SPI_Read(uchar reg)
- //功能:NRF24L01的SPI時(shí)序
- //****************************************************************************************************
- uchar SPI_Read(uchar reg)
- {
- uchar reg_val;
- CSN = 0; // CSN low, initialize SPI communication...
- SPI_RW(reg); // Select register to read from..
- reg_val = SPI_RW(0); // ..then read registervalue
- CSN = 1; // CSN high, terminate SPI communication
- return(reg_val); // return register value
- }
- //****************************************************************************************************
- //*功能:NRF24L01讀寫寄存器函數(shù)
- //****************************************************************************************************
- uchar SPI_RW_Reg(uchar reg, uchar value)
- {
- uchar status;
- CSN = 0; // CSN low, init SPI transaction
- status = SPI_RW(reg); // select register
- SPI_RW(value); // ..and write value to it..
- CSN = 1; // CSN high again
- return(status); // return nRF24L01 status uchar
- }
- //****************************************************************************************************
- uchar SPI_Read_Buf(uchar reg, uchar *pBuf, uchar bytes)
- {
- uchar status,byte_ctr;
- CSN = 0; // Set CSN low, init SPI tranaction
- status = SPI_RW(reg); // Select register to write to and read status byte
- for(byte_ctr=0;byte_ctr<bytes;byte_ctr++)
- pBuf[byte_ctr] = SPI_RW(0); // Perform SPI_RW to read byte from nRF24L01
- CSN = 1; // Set CSN high again
- return(status); // return nRF24L01 status byte
- }
- //*********************************************************************************************************
- //*函數(shù):uint SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars)
- //*功能: 用于寫數(shù)據(jù):為寄存器地址,pBuf:為待寫入數(shù)據(jù)地址,uchars:寫入數(shù)據(jù)的個(gè)數(shù)
- //*********************************************************************************************************
- uchar SPI_Write_Buf(uchar reg, uchar *pBuf, uchar uchars)
- {
- uchar status,uchar_ctr;
-
- CSN = 0; //SPI使能
- status = SPI_RW(reg);
- for(uchar_ctr=0; uchar_ctr<uchars; uchar_ctr++) //
- SPI_RW(*pBuf++);
- CSN = 1; //關(guān)閉SPI
- return(status);
- }
- //********** nrf收發(fā)程序 **********
- void nrf_RxTx(uchar mod_nrf,uchar *buff) //NRF24L01收發(fā)程序
- {
- static uchar mod_nrf_b;//static 地址不釋放
- //******進(jìn)入發(fā)射模式******
- if(mod_nrf == 't')
- {
- if(mod_nrf_b != 't')
- {
- mod_nrf_b = 't';
- CE = 0;
- SPI_RW_Reg(WRITE_REG+STATUS,0xff); //清除中斷標(biāo)志
- SPI_RW_Reg(FLUSH_TX,0x00); //清除TX_FIFO寄存器
- SPI_RW_Reg(WRITE_REG + CONFIG,0x7e);//IRQ引腳不顯示中斷 上電 發(fā)射模式 1~16CRC校驗(yàn)
- CE = 1;
- delayus(130);//從CE = 0 到 CE = 1;即待機(jī)模式到收發(fā)模式,需要最大130us
- }
-
- //******發(fā)送數(shù)據(jù)******
- CE = 0; //StandBy I模式
- SPI_Write_Buf(WRITE_REG + RX_ADDR_P0, TX_ADDRESS, TX_ADR_WIDTH); // 裝載接收端地址
- SPI_Write_Buf(WR_TX_PLOAD,buff,TX_PLOAD_WIDTH); // 裝載數(shù)據(jù)
- CE = 1; //置高CE激發(fā)數(shù)據(jù)發(fā)送
- delayus(130);//從CE = 0 到 CE = 1;即待機(jī)模式到收發(fā)模式,需要最大130us
-
- delayus(100); //給發(fā)送數(shù)據(jù)一點(diǎn)時(shí)間 發(fā)送延時(shí)可以比接收少
- sta = SPI_Read(STATUS);//讀取狀態(tài)寄存器的值
- SPI_RW_Reg(WRITE_REG+STATUS,sta);//清除對(duì)應(yīng)的中斷
-
- if(TX_DS == 1)//發(fā)送成功再清除tx fifo寄存器
- {
- CE = 0;
- SPI_RW_Reg(FLUSH_TX,0x00); //清除tx fifo寄存器 //********重要*********
- CE = 1;
- }
- }
- //******進(jìn)入接收模式******
- else if(mod_nrf == 'r')//接收模式
- {
- if(mod_nrf_b != 'r')
- {
- mod_nrf_b = 'r';
- CE = 0;
- SPI_RW_Reg(WRITE_REG+STATUS,0xff); //清除中斷標(biāo)志
- SPI_RW_Reg(FLUSH_RX,0x00); //清除RX_FIFO寄存器
- SPI_RW_Reg(WRITE_REG + CONFIG, 0x7f);//IRQ引腳不顯示中斷 上電 接收模式 1~16CRC校驗(yàn)
- CE = 1;
- delayus(130);//從CE = 0 到 CE = 1;即待機(jī)模式到收發(fā)模式,需要最大130us
- }
- delayus(500); //不能少 值可調(diào) 給接收數(shù)據(jù)一點(diǎn)時(shí)間
- sta = SPI_Read(STATUS);
- SPI_RW_Reg(WRITE_REG+STATUS,sta);
- if(RX_DR == 1)
- {
- CE = 0;
- SPI_Read_Buf(RD_RX_PLOAD,buff,RX_PLOAD_WIDTH);//讀取數(shù)據(jù) 存入數(shù)組
- SPI_RW_Reg(FLUSH_RX,0x00);//清除rx fifo寄存器 數(shù)據(jù)不抖動(dòng)
- CE = 1;
- }
- }
- }
- //************* 外部中斷 *********************
- void int1() interrupt 2 //檢測(cè)到硬幣時(shí)發(fā)生中斷 P3.3引腳
- {
- while(1)//檢測(cè)到硬幣時(shí),即時(shí)沖出賽道也能重新回去
- {
- if(PROBE_L == 1 && PROBE_M == 0 && PROBE_R == 0)
- { probe_before = 'l';break; }
- else if(PROBE_L == 0 && PROBE_M ==0 && PROBE_R == 1)
- { probe_before = 'r';break; }
- }
- EX1 = 0; //禁止中斷 等到P33電平由0變1時(shí)再允許中斷
- see_coin = 1;
- num_coin++;
- }
- //******************** 定時(shí)器 ***********************
- void timer_init()//定時(shí)器初始化
- {
- // ET0 = 1;
- ET1 = 1;
- TMOD = 0x11;// 定時(shí)器0,1 :不響應(yīng)外部引線,定時(shí)器方式(為振蕩器12分頻計(jì)數(shù)) 模式1(16位計(jì)數(shù)器)
- TCON = 0;
- // t0_h = 0x3C; //0x3CB0 = 65536 -50000= 15536 50ms中斷一次
- // t0_l = 0xB0;
- // TH0 = t0_h;
- // TL0 = t0_l;
- t1_h = 0xFC;
- t1_l = 0x18;//0xFC18 = 64536 1000 = 65536 - 64536 1ms中斷一次
- TH1 = t1_h;
- TL1 = t1_l;
- }
- /*
- //**********定時(shí)器0**********
- void timer0() interrupt 1 //定時(shí)器默認(rèn)12T 即12MHz晶振下 THi TLi 每1us加1,與c51單片機(jī)兼容
- {
- TH0 = t0_h; //0x3CAF = 65535 -50000= 15535 50ms中斷一次
- TL0 = t0_l;
- t0_flag++;
- if(t0_flag == 20) //1s
- {
- t0_flag = 0;
- time_of_move++;//每過一秒 小車行駛時(shí)間變量+1
- }
- }*/
- //**********定時(shí)器1**********
- void timer1() interrupt 3 //每1ms中斷一次
- {
- TH1 = 0xFC;
- TL1 = 0x17;
- t1_flag++;
- t1_flag_add++;
- t1_flag_time++;
- t1_flag_see_coin++;
- t1_flag_laserout++;
- if(t1_flag_time == 1000)
- {
- t1_flag_time = 0;
- time_of_move++;//每過一秒 小車行駛時(shí)間變量+1
- }
- }
- //************* PWM調(diào)速相關(guān)函數(shù) ****************
- void pca0()//P1.3輸出
- {
- CCAPM0 = 0x42;//8位PWM,無中斷模式
- CCAP0H = CCAP0L = 0xFF;//初始占空比設(shè)為0%
- }
- void pca1()//P1.4輸出
- {
- CCAPM1 = 0x42;
- CCAP1H = CCAP1L = 0xFF;
- }
- void pca_start()//設(shè)置pca工作模式
- {
- CMOD = 0x02;//2分頻(23kHz在人耳聽覺范圍之外),不允許CF中斷 允許中斷時(shí),運(yùn)行卡
- CCON = 0;
- CH = CL = 0;
- CR = 1;//pca開始計(jì)數(shù)
- }
- void pwm(unsigned long pwm0,unsigned long pwm1)
- {
- uint pwm0_temp,pwm1_temp;
- pwm0_temp = 255 - (pwm0*xs*255/1000); //pwm0 = 0 時(shí) pwm0_temp = 255;xs:系數(shù)0~10
- pwm1_temp = 255 - (pwm1*xs*255/1000);
- CCAP0H = CCAP0L = pwm0_temp;
- CCAP1H = CCAP1L = pwm1_temp;
- }
- //**************** LCD1602 ********************
- //******LCD基本函數(shù)******
- void busy_check() //忙碌檢測(cè)
- {
- RW = 1; //讀
- RS = 0; //指令寄存器
- LCD_DATA = 0xFF;//實(shí)驗(yàn)證明讀數(shù)時(shí)要將I/O口要置1
- LCDEN = 0;
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- LCDEN = 1;// EN高電平讀信息 負(fù)跳變執(zhí)行指令
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- while(1)
- {
- if(LCD_BUSY == 0)//P07 == 0跳出循環(huán)
- break;
- }
- }
- void lcdwrcom(uchar command)//寫指令
- {
- busy_check();
- RW = 0;//寫
- RS = 0;//指令寄存器
- LCD_DATA = command;
- LCDEN = 1;//負(fù)跳變寫入指令
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- LCDEN = 0;
- }
- void lcdwrdata(uchar lcd_data)//寫數(shù)據(jù) 數(shù)字、字母、標(biāo)點(diǎn)符號(hào)都是數(shù)據(jù)
- {
- busy_check();
- RW = 0;//寫
- RS = 1;//數(shù)據(jù)寄存器
- LCD_DATA = lcd_data;
- LCDEN = 1;//負(fù)跳變寫入指令
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- LCDEN = 0;
- }
- void lcd_init()
- {
- delayms(20);//必要 lcd1602上電到電壓穩(wěn)定需要時(shí)間
- RW = 0;//寫
- RS = 0;//指令寄存器
- LCD_DATA = 0x38;// 0x38設(shè)置顯示模式為:16X2 顯示,5X7 點(diǎn)陣,8 位數(shù)據(jù)接口'
- LCDEN = 1;
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- LCDEN = 0;
- delayms(5);
- lcdwrcom(0x0c);//打開顯示 無光標(biāo) 不閃爍
- lcdwrcom(0x06);//指令3 光標(biāo)右移 屏幕所有文字移動(dòng)無效
- lcdwrcom(0x01);// 清顯示,光標(biāo)復(fù)位到地址00H位置。
- }
- //****** LCD擴(kuò)展函數(shù) ******
- void address(uchar x,uchar y) //定位下一步要寫數(shù)的地址
- {
- uchar location;
- if(x == 0)
- location = 0x80|y;
- else
- location = 0xC0|y;
- lcdwrcom(location);
- }
- void printchar(uchar x,uchar y,uchar letter)//顯示字母、單個(gè)字符
- {
- address(x,y);
- lcdwrdata(letter);
- }
- void printword(uchar x,uchar y,uchar *word) //顯示單詞(字符數(shù)組)
- {
- uchar i = 0;
- for(i = 0;word[i] != '\0';i++)
- {
- address(x,y + i);
- lcdwrdata(word[i]);
- }
- }
- void printuint(uchar x,uchar y,uchar num_ws_max,uint num)//顯示無符號(hào)整形 0~65535 x:行 y:列 num_ws_max 變量的最大位數(shù)
- {
- uchar i = 0;
- uchar str[5] = {0x20,0x20,0x20,0x20,0x20};
- if(num >= 10000)
- {
- str[0] = num/10000 + '0';
- str[1] = num%10000/1000 + '0';
- str[2] = num%1000/100 + '0';
- str[3] = num%100/10 + '0';
- str[4] = num%10 + '0';
- // str[5] = '\0'; //手動(dòng)加字符串結(jié)束標(biāo)志
- }
- else if(num >= 1000)
- {
- str[0] = num/1000 + '0';
- str[1] = num%1000/100 + '0';
- str[2] = num%100/10 + '0';
- str[3] = num%10 + '0';
- str[4] ='\0';
- }
- else if(num >= 100)
- {
- str[0] = num/100 + '0';
- str[1] = num%100/10 + '0';
- str[2] = num%10 + '0';
- str[3] = '\0';
- }
- else if(num >=10)
- {
- str[0] = num/10 + '0';
- str[1] = num%10 + '0';
- str[2] = '\0';
- }
- else if(num >= 0)
- {
- str[0] = num + '0';
- str[1] = '\0';
- }
-
- for(i = 0;i <= 5;i++) //uint類型 最大值65535 為5位數(shù)
- {
- if(str[i] != '\0' && i < num_ws_max)
- {
- address(x,y + i);
- lcdwrdata(str[i]);
- }
- else if(str[i] == '\0' && i < num_ws_max)
- {
- address(x,y+i);
- lcdwrdata(' ');//空格 // 實(shí)現(xiàn)功能:在此變量的位數(shù)范圍內(nèi),把沒數(shù)字的位存0x20(空白)
- //例如:最大有3位:999 當(dāng)變?yōu)?9時(shí),存為9+'0' 9+'0' 0x20
- }
- }
- }
- /*
- void printvolt(uchar x,uchar y,uint v) //將一個(gè)3位數(shù)除以100 保留兩位小數(shù) 可用來顯示電壓 0.00~5.00V
- {
- uchar str[4] = "0";
- uchar i = 0;
- str[0] = v/100 + '0';
- str[1] = '.';
- str[2] = v%100/10 + '0';
- str[3] = v%10 + '0';
- printword(x,y,str);
-
- }*/
- //*************** ADC ******************
- void adc_init() //adc初始化
- {
- EADC = 1; //允許ADC中斷
- SW_CH = SW_BH = SW_AH = 0;
- SW_CL = SW_BL = SW_AL = 0;
- ADC_CONTR = 0x8D;//使用P1.5口 540個(gè)時(shí)鐘周期轉(zhuǎn)換一次
- // ADC_CONTR = 0xCD;//使用P1.5口 180個(gè)時(shí)鐘周期轉(zhuǎn)換一次
- P1ASF = 0x20;//P1口 P1.5作為模擬功能A/D使用
- }
- void adc() interrupt 5
- {
- unsigned long int volt_temp; //涉及到*500的計(jì)算 所以定義出無符號(hào)長整形
- uchar i = 0;
- // ADC_CONTR = 0xC5;// A/D轉(zhuǎn)換完成 ADC_FLAG軟件置零 停止轉(zhuǎn)換
- ADC_CONTR = 0x85;
- adc5[times_adc] = ADC_RES;
- volt_temp = ADC_RES;
- volt = volt_temp*500/255; //volt_temp 設(shè)為無符號(hào)長整形 先乘再除保證精度。將0~5的數(shù)拉長為0~500,提高精度。
- if(times_adc < 48 )
- {
- times_adc++; //0~48
- SW_CH = 4&(times_adc/7); //按位與 接通cd4051正確的行
- SW_BH = 2&(times_adc/7);
- SW_AH = 1&(times_adc/7);
- SW_CL = 4&(times_adc%7); //接通cd4051正確的列
- SW_BL = 2&(times_adc%7);
- SW_AL = 1&(times_adc%7);
- }
- else //找出最小值,當(dāng)最小值小于某個(gè)值說明激光打在adc_min這個(gè)區(qū)域
- {
- times_adc = 0;
- SW_CH = SW_BH = SW_AH = 0;
- SW_CL = SW_BL = SW_AL = 0; //為下一次掃描cd4051做準(zhǔn)備
- //***** 判斷最小值 ******
- num_vmin = 0;
- for(i = 0;i < 49;i++)
- {
- if(adc5[i] <= adc5[num_vmin])
- num_vmin = i;
- }
- }
- // ADC_CONTR = 0xCD;//開始轉(zhuǎn)換
- ADC_CONTR = 0x8D;
- }
- void move(uchar g_b_l,uchar g_b_r,uchar pwm0,uchar pwm1)
- //g_b_l: 'g'左輪前進(jìn) 'b' 左輪后退 ;g_b_r:'g':右輪前進(jìn) 'b'右輪后退 pwm_left:左輪占空比 pwm_right:右輪占空比
- {
- if(g_b_l == 'g')
- {
- LEFT_GO;
- /* left_mod[0] = 'G'; //數(shù)組只能在初始化時(shí)整體賦值 在這里left[] = "GO "是行不通的
- left_mod[1] = 'O';
- left_mod[2] = 0x20; //空值 打空格也行
- left_mod[3] = ' '; //空格
- left_mod[4] = '\0'; */
- }
- else if(g_b_l == 'b')
- {
- LEFT_BACK;
- /* left_mod[0] = 'B';
- left_mod[1] = 'A';
- left_mod[2] = 'C';
- left_mod[3] = 'K';
- left_mod[4] = '\0'; */
- }
- else if(g_b_l == 's')
- {
- LEFT_STOP;
- /* left_mod[0] = 'S';
- left_mod[1] = 'T';
- left_mod[2] = 'O';
- left_mod[3] = 'P';
- left_mod[4] = '\0'; */
- }
- if(g_b_r == 'g')
- {
- RIGHT_GO;
- /* right_mod[0] = 'G';
- right_mod[1] = 'O';
- right_mod[2] = 0x20; //空值
- right_mod[3] = 0x20; //空值
- right_mod[4] = '\0'; */
- }
- else if(g_b_r == 'b')
- {
- RIGHT_BACK;
- /* right_mod[0] = 'B';
- right_mod[1] = 'A';
- right_mod[2] = 'C';
- right_mod[3] = 'K';
- right_mod[4] = '\0';*/
- }
- else if(g_b_r == 's')
- {
- RIGHT_STOP;
- /* right_mod[0] = 'S';
- right_mod[1] = 'T';
- right_mod[2] = 'O';
- right_mod[3] = 'P';
- right_mod[4] = '\0'; */
- }
- if(pwm0 >= 0 && pwm0 <= 100 && pwm1 >= 0 && pwm1 <= 100)
- {
- pwm(pwm0,pwm1);
- }
- else //值不在0 ~100 的范圍
- {
- pwm(0,0);
- }
- }
- void track(uchar pwm0,uchar pwm1)//循跡函數(shù)
- {
- if(PROBE_L == 0 && PROBE_M ==0 && PROBE_R == 0) //處理上一步探頭狀態(tài) 避免沖出跑道
- {
- if(probe_before == 'l') //上一步左轉(zhuǎn)
- {
- move('b','g',86,86);//左輪?馬力向后轉(zhuǎn) 右輪?馬力向前轉(zhuǎn) 即左轉(zhuǎn)
- }
- else if(probe_before == 'g') //上一步前進(jìn)
- {
- move('g','g',pwm0,pwm1);//左右輪分別以pwm0 pwm1 馬力前進(jìn)
- // move('b','g',pwm0,pwm1);//左輪pwm0馬力向后轉(zhuǎn) 右輪pwm1馬力向前轉(zhuǎn) 即左轉(zhuǎn)
- //繼續(xù)前進(jìn)的話容易出現(xiàn)失誤,跑出賽道。選擇左轉(zhuǎn),右轉(zhuǎn)均可
- }
- else if(probe_before == 'r') //上一步右轉(zhuǎn)
- {
- move('g','b',86,86);//左輪?馬力向前轉(zhuǎn) 右輪?馬力向后轉(zhuǎn) 即右轉(zhuǎn)
- }
- }
- else if(PROBE_L == 0 && PROBE_M == 1 && PROBE_R == 0) //中部探頭在黑帶處 前進(jìn)
- {
- probe_before = 'g';//前進(jìn)標(biāo)志
- move('g','g',pwm0,pwm1);//前進(jìn)
- }
- else if(PROBE_L == 1 && PROBE_M == 1 && PROBE_R == 0)
- {
- if(change_line_mod == '?')
- {
- times_probe_l++;
- }
- probe_before = 'l'; //左轉(zhuǎn)標(biāo)志
- move('b','g',85,85);//左轉(zhuǎn)
- }
- else if(PROBE_L == 1 && PROBE_M ==0 && PROBE_R == 0)
- {
- if(change_line_mod == '?')
- {
- times_probe_l++;
- }
- probe_before = 'l'; //左轉(zhuǎn)標(biāo)志
- move('b','g',86,86);//左轉(zhuǎn)
- }
- else if(PROBE_L == 0 && PROBE_M == 1 && PROBE_R == 1)
- {
- if(change_line_mod == '?') //未定值時(shí)
- {
- times_probe_r++;
- }
- probe_before = 'r';//右轉(zhuǎn)標(biāo)志
- move('g','b',85,85);//右轉(zhuǎn)
- }
- else if(PROBE_L == 0 && PROBE_M ==0 && PROBE_R == 1)
- {
- if(change_line_mod == '?') //未定值時(shí)
- {
- times_probe_r++;
- }
- probe_before = 'r';//右轉(zhuǎn)標(biāo)志
- move('g','b',86,86);//右轉(zhuǎn)
- }
- else if(PROBE_L == 1 && PROBE_M == 1 && PROBE_R == 1) //賽道中 111表示橫著的黑帶,標(biāo)志著下一個(gè)步驟
- {
- while(1)
- {
- move('g','g',pwm0,pwm1);//前進(jìn)
- if(PROBE_L == 0 || PROBE_M == 0 || PROBE_R == 0)
- {
- if(step < 255) //防止溢出變?yōu)?
- step++;
- break;
- }
- }
- }
- /* else if(PROBE_L == 1 && PROBE_M ==0 && PROBE_R == 1) //賽道上不出現(xiàn)這個(gè)情況
- {
- }
- */
- if(change_line_mod == '?') //為change_line_mod的定值
- {
- if(times_probe_l == 15 || times_probe_r == 15) //任意一個(gè)探測(cè)到黑帶數(shù)達(dá)到15 開始確定change_line_mod的值
- {
- if(times_probe_l > times_probe_r)
- change_line_mod = 'l'; //左轉(zhuǎn)進(jìn)入內(nèi)圈
- else
- change_line_mod = 'r'; //右轉(zhuǎn)進(jìn)入內(nèi)圈
- }
- }
- }
- void track_all(uchar pwm_l,uchar pwm_r)
- {
- if(angle < 720)
- {
- /* if(P33 == 1 && EX1 == 0 && flag_see_coin == 0)
- EX1 = 1;*/
- if(see_coin == 1 && P33 == 1) //檢測(cè)到硬幣 且探頭脫離硬幣 防止多次檢測(cè)同一個(gè)硬幣
- {
- move('s','s',0,0);//停車
- if(flag_see_coin == 0) //剛檢測(cè)到硬幣時(shí) 置零t1_flag_see_coin 開始計(jì)時(shí)
- {
- flag_see_coin = 1; //已經(jīng)檢測(cè)到硬幣
- t1_flag_see_coin = 0; //置零t1_flag_see_coin 開始計(jì)時(shí)
- }
- if(t1_flag_see_coin < 500)
- { LED = 1; SPK = 1; }
- else if(t1_flag_see_coin < 1000)
- { LED = 0; SPK = 0; }
- else if(t1_flag_see_coin < 1500)
- { LED = 1; SPK = 1; }
- else if(t1_flag_see_coin < 2000)
- { LED = 0; SPK = 0; }
- else
- {
- EX1 = 1;
- see_coin = 0; //回去執(zhí)行檢測(cè)到硬幣之前的else語句
- flag_see_coin = 0;
- }
- }
- else if(step == 0)
- {
- if(PROBE_L == 1 && PROBE_M == 1 && PROBE_R == 1)
- {
- move('g','g',83,83);
- while(1)
- {
- if(PROBE_L == 0 || PROBE_M == 0 || PROBE_R == 0)
- {
- step = 1;
- break;
- }
- }
- }
- }
- else if(step == 1)
- {
- track(pwm_l,pwm_r);
- }
- else if(step == 2)
- {
- track(pwm_l + 5,pwm_r + 5); //加速行駛
- }
- else if( step == 3)
- {
- track(pwm_l,pwm_r);
- }
- else if(step == 4) //進(jìn)入內(nèi)圈 聲光提示
- {
- if(change_line == 1)//第1步 駛出橫黑帶
- {
- LED = SPK = 1;
- move('g','g',pwm_l,pwm_r);
- if(PROBE_L == 0 || PROBE_M == 0 || PROBE_R == 0)
- change_line = 2;
- }
- else if(change_line == 2)//第2步 讓與轉(zhuǎn)向方式相異的邊探頭探測(cè)到黑帶
- {
- LED = SPK = 0;
- if(change_line_mod == 'l') //左轉(zhuǎn) 探頭狀態(tài)001 (讓右探頭探測(cè)黑帶,再進(jìn)入下一步)
- {
- move('b','g',86,86);
- if(PROBE_L == 0 && PROBE_M == 0 && PROBE_R == 1)
- change_line = 3;
- }
- else if(change_line_mod == 'r') //右轉(zhuǎn) 探頭狀態(tài)100
- {
- move('g','b',86,86);
- if(PROBE_L == 1 && PROBE_M == 0 && PROBE_R == 0)
- change_line = 3;
- }
- }
- else if(change_line == 3) //第3步 轉(zhuǎn)向前進(jìn)交替
- {
- if(change_line_mod == 'l') //左轉(zhuǎn)前進(jìn)交替
- {
- LED = SPK = 1;
- move('b','g',86,86);
- delayms(10);
-
- LED = SPK = 0;
- move('g','g',pwm_l + 15,pwm_r + 15);
- delayms(5);
- if(PROBE_L == 1 || PROBE_M == 1)
- {
- LED = SPK = 0;
- change_line = 0;
- step = 5;
- }
- }
- else if(change_line_mod == 'r') //右轉(zhuǎn)前進(jìn)交替
- {
- LED = SPK = 1;
- move('g','b',86,86);
- delayms(10);
-
- LED = SPK = 0;
- move('g','g',pwm_l + 15,pwm_r + 15);
- delayms(5);
- if(PROBE_L == 1 || PROBE_M == 1)
- {
- LED = SPK = 0;
- change_line = 0;
- step = 5;
- }
- }
- }
- }
- else
- {
- track(pwm_l,pwm_r);
- }
- }
- else if(angle >= 720)
- {
- move('s','s',0,0);
- }
- }
- void laser_guide(uchar pwm) //激光引導(dǎo)模式
- {
- uchar x;
- uchar y;
-
- if(adc5[num_vmin] < 210)// 確保有激光打到光敏電阻上才執(zhí)行
- {
- flag_laserout = 0;
- x = num_vmin/7; //對(duì)7取整得到行數(shù)
- y = num_vmin%7; //對(duì)7取余得到列數(shù)
- num_vmin_before = num_vmin;
- if(x >= 2 && x <= 4 && y <= 2)
- {
- move('g','g',pwm - 5,pwm - 5);//前進(jìn) 轉(zhuǎn)彎比直走費(fèi)勁
- }
- else if(x >= 2 && x <= 4 && y >= 4)
- {
- move('b','b',pwm - 5,pwm - 5);//后退
- }
- else if(x >= 5)
- {
- move('b','g',pwm,pwm);//左轉(zhuǎn) 轉(zhuǎn)彎比直走費(fèi)勁
- }
- else if(x <= 2)
- {
- move('g','b',pwm,pwm);//右轉(zhuǎn)
- }
- else
- {
- move('s','s',0,0);//停止
- }
- }
- else //激光脫離 保持原行駛狀態(tài)一段時(shí)間,希望能重新感應(yīng)到
- {
- x = num_vmin_before/7; //對(duì)7取整 得到行數(shù)
- y = num_vmin_before%7; //對(duì)7取余 得到列數(shù)
- if(flag_laserout == 0) //剛脫離感光板
- {
- flag_laserout = 1;
- t1_flag_laserout = 0; //置零 每1ms加1
- }
- if(t1_flag_laserout < 300 ) //?ms
- {
- if(x >= 2 && x <= 4 && y <= 2)
- {
- move('g','g',pwm - 5,pwm - 5);//前進(jìn)
- }
- else if(x >= 2 && x <= 4 && y >= 4)
- {
- move('b','b',pwm - 5,pwm - 5);//后退
- }
- else if(x >= 5)
- {
- move('b','g',pwm,pwm);//左轉(zhuǎn)
- }
- else if(x <= 2)
- {
- move('g','b',pwm,pwm);//右轉(zhuǎn)
- }
- else
- {
- move('s','s',0,0);//停止
- }
- }
- else
- {
- move('s','s',0,0);
- num_vmin_before = 24;
- }
-
- }
- }
- //************ 判斷NRF24L01是否聯(lián)機(jī) ************
- uchar isonline(uint time) //返回0:離線、超時(shí) ,返回1:在線或未超時(shí)
- {
- static uchar addone;
- static uchar addone_b;
- static uchar flag_add;
- uchar revalue;
- addone = RxBuf[12];
- if(addone == addone_b) //值不變 發(fā)送方可能離線 當(dāng)值保持不變的時(shí)間超過參數(shù)time,則視發(fā)送方為離線
- {
- if(flag_add == 0)
- {
- flag_add = 1;
- t1_flag_add = 0;//t1_flag_add 置0;t1_flag_add在定時(shí)器1中斷函數(shù)中 每1ms自加1
- }
- if(t1_flag_add < time)//未超時(shí)
- {
- revalue = 1;
- }
- else if(t1_flag_add >= time)//超時(shí)
- {
- t1_flag_add = time;
- revalue = 0; //超時(shí) 發(fā)送端離線
- }
- }
- else if(addone != addone_b)
- {
- addone_b = addone;
- flag_add = 0;
- revalue = 1;//值在變 發(fā)送端在線 未失聯(lián)
- }
- return(revalue);//返回1:在線 , 0:離線
- }
- void rc_ol(uchar pwm_ctrl_l,uchar pwm_ctrl_r) //rc 遙控 模式 發(fā)送方在線
- {
- uchar mod_ctrl_l;
- uchar mod_ctrl_ls; //用于顯示+ -
- uchar mod_ctrl_r;
- uchar mod_ctrl_rs; //用于顯示+ -
- uint pwm_ctrl_temp; //防止數(shù)據(jù)溢出
- if(pwm_ctrl_l >= 129 && pwm_ctrl_l <= 255)//129~255 差值126
- {
- mod_ctrl_l = 'g';
- mod_ctrl_ls = '+';//前進(jìn)
- pwm_ctrl_temp = pwm_ctrl_l;
- pwm_ctrl_l = (pwm_ctrl_temp - 129)*100/126;//將129~255轉(zhuǎn)換成0~100
- }
- else if(pwm_ctrl_l >= 0 && pwm_ctrl_l <= 126)
- {
- mod_ctrl_l = 'b';
- mod_ctrl_ls = '-';
- pwm_ctrl_temp = pwm_ctrl_l;
- pwm_ctrl_l = 100 - (pwm_ctrl_temp*100/126); //將0~126轉(zhuǎn)換為100~0
- }
- else //包括等于 127,128 其他
- {
- mod_ctrl_l = 's';
- mod_ctrl_ls = ' ';
- pwm_ctrl_l = 0;
- }
- if(pwm_ctrl_r >= 129 && pwm_ctrl_r <= 255)//129~255 差值126
- {
- mod_ctrl_r = 'g';//前進(jìn)
- mod_ctrl_rs = '+';
- pwm_ctrl_temp = pwm_ctrl_r;
- pwm_ctrl_r = (pwm_ctrl_temp - 129)*100/126;//將129~255轉(zhuǎn)換成0~100
- }
- else if(pwm_ctrl_r >= 0 && pwm_ctrl_r <= 126)
- {
- mod_ctrl_r = 'b';
- mod_ctrl_rs = '-';
- pwm_ctrl_temp = pwm_ctrl_r;
- pwm_ctrl_r = 100 - (pwm_ctrl_temp*100/126); //將0~126轉(zhuǎn)換為100~0
- }
- else //包括等于 127,128 其他
- {
- mod_ctrl_r = 's';
- mod_ctrl_rs = ' ';
- pwm_ctrl_r = 0;
- }
- move(mod_ctrl_l,mod_ctrl_r,pwm_ctrl_l,pwm_ctrl_r);
- if(string_cmp(lcd_code,"rc_ol") != 1)
- {
- lcdwrcom(0x01);//清顯示
- string_copy(lcd_code,"rc_ol");
- }
- printword(0,0,"MODE:RC");
- printword(0,8,"TIME:");
- printuint(0,13,3,time_of_move);
- printword(1,0,"L:");
- printchar(1,2,mod_ctrl_ls);
- printuint(1,3,3,pwm_ctrl_l);
- printword(1,8,"R:");
- printchar(1,10,mod_ctrl_rs);
- printuint(1,11,3,pwm_ctrl_r);
-
- }
- //******************** 主函數(shù) ***********************
- void main()
- {
- uchar addone_tx = 0;
- uchar pwm_ctrl_l;
- uchar pwm_ctrl_r;
- uint pwm_rx = 0;
- uint pwm_laser = 0;
- ……………………
- …………限于本文篇幅 余下代碼請(qǐng)從51黑下載附件…………
復(fù)制代碼
所有資料51hei提供下載:
小車.zip
(107.05 KB, 下載次數(shù): 57)
2017-7-8 21:24 上傳
點(diǎn)擊文件名下載附件
程序,原理圖
|
評(píng)分
-
查看全部評(píng)分
|