PIC單片機實例三:基于PROTEUS模擬的雙機異步通信
公司的數(shù)控面板和控制板的連線是25芯的,但沒有既細(xì)又長的配套線,所以一向都是自己用細(xì)線做的,但問題也就多了,乘著這幾天正學(xué)串口通信,用PIC單片機改裝了兩塊板,實現(xiàn)了雙機之間的異步通信,并用PROTEUS模擬了出來,跟有興趣的朋友共享.
一.原理圖
功能介紹:
(1).U1單片機控制4X5的矩陣鍵盤和十個指示燈,名稱按圖所示.
(2).U2單片機控制18個繼電器.
(3).按鍵”選擇槍1”,”選擇槍2”,”選擇槍3”,”選擇槍4”,”PREHEAT”,”CUTTING”,”HEIGHT”,”RETRACE”,”PLASMA”這9個按鍵是一鍵控制相對應(yīng)的繼電器的開關(guān).就是說按一下為開,送開保持原先狀態(tài),再按一下為關(guān),送開保持,即實現(xiàn)一個D觸發(fā)器的電平翻轉(zhuǎn)功能.
(4).按鍵”1 UP”,”1 DOWN”,”2 UP”,”2 DOWN”,”3 UP”,”3 DOWN”,”4 UP”,”4 DOWN”,”ALL UP”,”ALL DOWN”,”IGNITION”為點動按鍵,即按下為開,繼電器吸合,送開為關(guān),繼電器放開.
(5).所用單片機為P16F873A
二.程序
為觀察方便,特把圖分為發(fā)送部分和接收部分,并分別編程.
1. 發(fā)送部分
原理圖如下所示
/***********************************************************************
* 文件標(biāo)題:CNC-USART-1 *
* 編制日期:2007.12.19 *
* 編制人: wujieflash*
* 程序用途:用于數(shù)控切割機上的面板通信(發(fā)送部分)*
* 配套圖紙:CNC-02*
* 版本號: V1.0 *
***********************************************************************/
#include
//函數(shù)聲明
void initial();
void delay();
void key_scan();
void key_serve();
void send_usart();
//定義變量
unsigned int i,j,k1,k2,k3,k4,k5,k6,k7,k8,k9,k10;
//子程序
//初始化子程序
void initial()
{
ADCON1=0x06;//設(shè)置為普通數(shù)字引腳
TRISC0=0;//鍵盤四根行線設(shè)置為輸出
TRISC1=0;
TRISC2=0;
TRISC3=0;
TRISC4=1;//鍵盤五根列線設(shè)置為輸入
TRISC5=1;
TRISA2=1;
TRISA3=1;
TRISA4=1;
TRISB=0;
PORTB=0;
TRISA0=0;
RA0=0;
TRISA1=0;
RA1=0;
RC0=0;//四根行線先送低電平
RC1=0;
RC2=0;
RC3=0;
//USART部件初始化
SPBRG=0x19;//設(shè)置波特率為9600bps
TXSTA=0x04;//選擇異步高速8位數(shù)據(jù)傳輸模式
RCSTA=0x80;//允許串行端口工作
TRISC6=1;//設(shè)置為高阻態(tài),防止干擾
TRISC7=1;
}
//延時子程序
void delay()
{
for(i=2000;i--;)
continue;
}
//鍵盤掃描子程序
void key_scan()
{
while(1)
{
if((RC4==0)||(RC5==0)||(RA2==0)||(RA3==0)||(RA4==0))//是否有鍵按下
{
break;
}
}
delay();
if((RC4==0)||(RC5==0)||(RA2==0)||(RA3==0)||(RA4==0))//確認(rèn)有鍵按下
{
key_serve();
}
else
{
j=0x00;
send_usart();
}
}
//按鍵服務(wù)子程序
void key_serve()
{
RC1=1;//先置RC0為低電平,剩余三根行線為高電平
RC2=1;
RC3=1;
RC0=0;
if(RC4==0)//按鍵1 “select 1"
{
k1++;
k1=k1%2;
if(k1==1)//奇數(shù)次為開
{
j=0x01;
send_usart();
RB0=1;//指示燈亮
}
if(k1==0)//偶數(shù)次為關(guān)
{
j=0x15;
send_usart();
RB0=0;//指示燈滅
}
}
if(RC5==0)//按鍵2 "1 up"
{
j=0x02;
send_usart();
}
if(RA2==0)//按鍵3 "1 down"
{
j=0x03;
send_usart();
}
if(RA3==0)//按鍵4 "select 2"
{
k2++;
k2=k2%2;
if(k2==1)//奇數(shù)次為開
{
j=0x04;
send_usart();
RB1=1;
}
if(k2==0)//偶數(shù)次為關(guān)
{
j=0x16;
send_usart();
RB1=0;
}
}
if(RA4==0)//按鍵5 “2 up"
{
j=0x05;
send_usart();
}
RC0=1;//置RC1為低電平,剩余行線為高
RC2=1;
RC3=1;
RC1=0;
if(RC4==0)//按鍵6 "2 down"
{
j=0x06;
send_usart();
}
if(RC5==0)//按鍵7 "select 3"
{
k3++;
k3=k3%2;
if(k3==1)
{
j=0x07;
send_usart();
RB2=1;
}
if(k3==0)
{
j=0x17;
send_usart();
RB2=0;
}
}
if(RA2==0)//按鍵8 "3 up"
{
j=0x08;
send_usart();
}
if(RA3==0)//按鍵9 "3 down"
{
j=0x09;
send_usart();
}
if(RA4==0)//按鍵10 "select 4"
{
k4++;
k4=k4%2;
if(k4==1)
{
j=0x0a;
send_usart();
RB3=1;
}
if(k4==0)
{
j=0x18;
send_usart();
RB3=0;
}
}
RC0=1;//置RC2為低電平,剩余為高
RC1=1;
RC3=1;
RC2=0;
if(RC4==0)//按鍵11 "4 up"
{
j=0x0b;
send_usart();
}
if(RC5==0)//按鍵12 "4 down"
{
j=0x0c;
send_usart();
}
if(RA2==0)//按鍵13 "all up"
{
j=0x0d;
send_usart();
}
if(RA3==0)//按鍵14 "all down"
{
j=0x0e;
send_usart();
}
if(RA4==0)//按鍵15 "preheat"
{
k5++;
k5=k5%2;
if(k5==1)
{
j=0x0f;
send_usart();
RB4=1;
}
if(k5==0)
{
j=0x19;
send_usart();
RB4=0;
}
}
RC0=1;//置RC3為低,剩余為高
RC1=1;
RC2=1;
RC3=0;
if(RC4==0)//按鍵16 "cutting"
{
k6++;
k6=k6%2;
if(k6==1)
{
j=0x10;
send_usart();
RB5=1;
}
if(k6==0)
{
j=0x1a;
send_usart();
RB5=0;
}
}
if(RC5==0)//按鍵17 "height"
{
k7++;
k7=k7%2;
if(k7==1)
{
j=0x11;
send_usart();
RB6=1;
}
if(k7==0)
{
j=0x1b;
send_usart();
RB6=0;
}
}
if(RA2==0)//按鍵18 "ignition"
{
j=0x12;
send_usart();
RB7=1;
}
if(RA3==0)//按鍵19 "retrace"
{
k9++;
k9=k9%2;
if(k9==1)
{
j=0x13;
send_usart();
RA0=1;
}
if(k9==0)
{
j=0x1d;
send_usart();
RA0=0;
}
}
if(RA4==0)//按鍵20 "oxy/plasma"
{
k10++;
k10=k10%2;
if(k10==1)
{
j=0x14;
send_usart();
RA1=1;
}
if(k10==0)
{
j=0x1e;
send_usart();
RA1=0;
}
}
RC0=0;//置四根行線為低電平
RC1=0;
RC2=0;
RC3=0;
while(1)
{
if((RC4==1)&&(RC5==1)&&(RA2==1)&&(RA3==1)&&(RA4==1))//等鍵松開
break;
}
RB7=0;//關(guān)“IGNITION”指示燈
j=0x00;
send_usart();
}
//命令發(fā)送子程序
void send_usart()
{
TXEN=1;//發(fā)送允許
CREN=1;//接收允許
TXREG=j;
while(1)
{
if(TXIF==1)break;//等待發(fā)送完成
}
while(1)
{
if(RCIF==1)break;//等待接收完成
}
RCREG=RCREG;//讀響應(yīng)字節(jié),清RCIF
}
//主程序
void main(void)
{
initial();
while(1)
{
key_scan();
}
}
2.接收部分
原理圖如下所示
/***********************************************************************
* 文件標(biāo)題:CNC-USART-2 *
* 編制日期:2007.12.19 *
* 編制人: 吳杰 *
* 程序用途:用于數(shù)控切割機上的面板通信(接收部分) *
* 配套圖紙:CNC-01*
* 版本號: V1.0*
***********************************************************************/
#include
//函數(shù)聲明
void initial();
void recevie_usart();
void rece_serve();
//定義變量
unsigned int rece;
//子程序
//初始化子程序
void initial()
{
ADCON1=0x06;//設(shè)置RA口為普通數(shù)字端口
TRISA=0;
PORTA=0;
TRISB=0;
PORTB=0;
TRISC=0;
PORTC=0;
//USART部件初始化
SPBRG=0x19;//設(shè)置波特率為9600bps
TXSTA=0x04;//選擇異步高速8位數(shù)據(jù)傳輸模式
RCSTA=0x80;//允許串行端口工作
TRISC6=1;//設(shè)置為高阻態(tài),防止干擾
TRISC7=1;
}
//接收子程序
void recevie_usart()
{
CREN=1;
TXEN=1;
while(1)
{
if(RCIF==1)break;//接收完畢
}
rece=RCREG;//讀取接收到的數(shù)據(jù),并清RCIF
TXREG=rece;//待發(fā)送的數(shù)據(jù)
while(1)
{
if(TXIF==1)break;//發(fā)送完畢
}
}
//接收服務(wù)子程序
void rece_serve()
{
switch(rece)
{
case 0x00:{
RC2=0;//繼電器“1 up"關(guān)
RC3=0;//繼電器"1 down"關(guān)
RC4=0;//繼電器”2 up"關(guān)
RC5=0;//繼電器“2 down"關(guān)
RA0=0;//繼電器”3 up"關(guān)
RA1=0;//繼電器“3 down"關(guān)
RA2=0;//繼電器”4 up"關(guān)
RA3=0;//繼電器“4 down"關(guān)
RB7=0;//繼電器“ignition"關(guān)
break;
}
case 0x01:{
RB0=1;//繼電器”1 select"開
break;
}
case 0x15:{
RB0=0;//繼電器“1 select"關(guān)
break;
}
case 0x02:{
RC2=1;//繼電器”1 up"開
break;
}
case 0x03:{
RC3=1;//繼電器”1 down"開
break;
}
case 0x04:{
RB1=1;//繼電器”2 select"開
break;
}
case 0x16:{
RB1=0;//繼電器”2 select"關(guān)
break;
}
case 0x05:{
RC4=1;//繼電器”2 up"開
break;
}
case 0x06:{
RC5=1;//繼電器”2 down"開
break;
}
case 0x07:{
RB2=1;//繼電器”3 select"開
break;
}
case 0x17:{
RB2=0;//繼電器”3 select"關(guān)
break;
}
case 0x08:{
RA0=1;//繼電器”3 up"開
break;
}
case 0x09:{
RA1=1;//繼電器”3 down"關(guān)
break;
}
case 0x0a:{
RB3=1;//繼電器”4 select"開
break;
}
case 0x18:{
RB3=0;//繼電器”4 select"關(guān)
break;
}
case 0x0b:{
RA2=1;//繼電器”4 up"開
break;
}
case 0x0c:{
RA3=1;//繼電器”4 down"開
break;
}
case 0x0d:{
RC6=1;//繼電器”all up"開
RC4=1;
RC2=1;
RA0=1;
break;
}
case 0x0e:{
RA1=1;//繼電器”all down"開
RC3=1;
RC5=1;
RC7=1;
break;
}
case 0x0f:{
RB4=1;//繼電器”preheat"開
break;
}
case 0x19:{
RB4=0;//繼電器”preheat"關(guān)
break;
}
case 0x10:{
RB5=1;////繼電器”cutting"開
break;
}
case 0x1a:{
RB5=0;//繼電器”cutting"關(guān)
break;
}
case 0x11:{
RB6=1;////繼電器”height"開
break;
}
case 0x1b:{
RB6=0;//繼電器”height"關(guān)
break;
}
case 0x12:{
RB7=1;//繼電器”ignition"開
break;
}
/*case 0x1c:{
RB7=0;//繼電器”ignition"關(guān)
break;
}*/
case 0x13:{
RC0=1;//繼電器”retrace"開
break;
}
case 0x1d:{
RC0=0;//繼電器”retrace"關(guān)
break;
}
case 0x14:{
RC1=1;//繼電器”plasma"開
break;
}
case 0x1e:{
RC1=0;//繼電器”plasma"關(guān)
break;
}
}
}
//主程序
void main()
{
initial();
while(1)
{
recevie_usart();
rece_serve();
}
}
三,總結(jié)
雖然板子用用也沒啥問題,但程序畢竟考慮的簡單了一些,如:沒有考慮故障處理的問題,我打算寫進(jìn)一段自動提示故障的程序,在兩板之間通信線出現(xiàn)問題不通的時候,閃爍指示燈提示.還有什么欠考慮的地方請大家一起幫忙!