打算设计一套一主二从的多机通信系统。主机发送自己的供电状态给从机,读取从机的扫描的按键数据。由于系统功能比较简单,考虑到modbus协议相对来说挺复杂,所以设计了一个简化的通信协议:1、主机、从机UART均为模式1。主机发送2个字节的数据给从机,第1个字节为地址字节,寻址,第2个字节是数据字节,用来将主机的供电状态发给从机,并读取从机按键状态。2个从机,有时候2台都接入系统,有时候只有1台接入系统。此为设计功能要求。
设计中,在程序初始化时,主机发送一次数据给从机0x01,启动通信。然后进入while(1)循环。在循环中,定时读取供电状态,调用串口驱动函数。通信过程:启动通信后,主机接收从机的数据,1,接收成功,解析地址,地址解析相符的话,解析数据,有数据,执行数据,并再次发送数据给0x01,无数据,寻址另一台从机。2、接收成功,解析地址,不相符,寻址另一台从机,3、计时时间内,未收到数据,认为接收失败,寻址另一台从机。
串口接收2个字节为1帧数据,接收2个字节完成后,即认为数据接受完成,置位帧接收完成标志。
从机接收主机发来的2个字节的数据,同样进行地址、数据解析,完成后,回发数据给主机。
上述为通信流程。帖程序:
主机程序:
main.c:
- # define _MAIN_C
- # include "config.h"
- # include "tmr_uart.h"
- # include "action.h"
- # include "main.h"
- uchar8 OCBuf[]={0xFF,0xFF};
- bit OCflag=0; //过流标志
- //uchar8 Powflag;
- uchar8 PowSta=0xFF; //供电状态标志
- uchar8 PowCNTR=0; //供电采集计数
- uchar8 TxdBuf[2]={0xFF,0xFF}; //发送缓冲
- uchar8 buf[2];
- bit Txdflag=0; //字节发送标志
- uchar8 RxdBuf[2]; //接收缓冲
- uchar8 cntRxd=0; //接收计数
- bit RxFr_Succ=0; //帧接收成功标志。
- bit TxFr_Succ=0; //帧发送成功标志
- bit RxFr_Fail=0; //帧接收失败标志
- uchar8 sl_select=0; //从机选择索引
- void main()
- {
- ROE=1; RA3=1; RA2=1; RA1=1; //释放所有输出
- Buz=0; //蜂鸣器响
- DelayX50ms(5); //
- Buz=1; //蜂鸣器关
- P1=0x00; //数据管全亮,检测数据管是否正常
- DelayX50ms(5);
- P1=0xFF; //关闭数据管
- DIR_485=0; //485通信处于接收状态
- ConfigTimer0(); //配置定时器0
- ConfigUART(); //配置UART
- UartSend(0x01); //发送数据给从机0x01.
- while(1)
- {
- OCProtect(); //检测过流保护
- PowCheck(10); //检测供电状态
- UartDriver(); //串口驱动
- }
- }
- //串口驱动
- void UartDriver()
- {
- switch(sl_select)
- {
- case 0: if(RxFr_Succ) //接收数据成功
- {
- RxFr_Succ=0;
- UartReceive(); //串口读数据
- UartAction(0xF1); //接收数据解析(含地址)
- if((buf[1]>=0x03)&&(buf[1]<=0x11)) //buf[1]>=0x03,且小于0x11,表示有数据
- {
- UartSend(0x01); //继续发数据给0x01从机
- }
- else //无数据
- {
- sl_select++; //从机选择索引+1
- UartSend(0x02); //给0x02发数据
- }
-
- }
- if(RxFr_Fail) //接收数据失败,(此从机不在线)
- {
- RxFr_Fail=0;
- UartSend(0xF2); //给0x02发数据
- sl_select++; //从机选择索引+1
- }
- break;
- case 1: if(RxFr_Succ) //接收数据成功
- {
- RxFr_Succ=0;
- UartReceive();
- if((buf[1]>=0x03)&&(buf[1]<=0x11)) //有数据
- {
- UartSend(0x02); //继续给从机0x02发数据
- }
- else //无数据
- {
- sl_select--; //从机索引-1
- UartSend(0x01); //发送数据给0x01
- }
- }
- if(RxFr_Fail) //数据接收失败(此从机不在线)
- {
- RxFr_Fail=0;
- UartSend(0x01); //发送数据给0x01
- sl_select--; //索引-1
- }
- break;
- default:sl_select=0; break;
- }
- }
- //串口发送函数,只发送2个字节.
- void UartSend(uchar8 addr)
- {
- uchar8 len=0;
- DIR_485=1;
- TxdBuf[0]=addr; //将要发送的从机的地址装入发送缓冲内
- while(len<2)
- {
- Txdflag=0;
- SBUF=TxdBuf[len++];
- while(!Txdflag);
- }
- TxFr_Succ=1; //置位发送成功标志
- DelayX10us(5);
- DIR_485=0;
- }
- //串口接收函数
- void UartReceive()
- {
- uchar8 len=0;
- uchar8 buf[2];
- while(len<2)
- {
- buf[len++]=RxdBuf[len++];
- }
- DelayX10us(5);
- }
- //串口中断函数
- void InterruptUART() interrupt 4
- {
- if(RI)
- {
- RI=0;
- RxdBuf[cntRxd++]=SBUF;
- if(cntRxd>=2)
- {
- cntRxd=0;
- RxFr_Succ=1; //接收成功
- RxFr_Fail=0;
- TxFr_Succ=0;
- }
- }
- if(TI)
- {
- TI=0;
- Txdflag=1;
- }
- }
- //T0中断函数
- void InterruptTimter0() interrupt 1
- {
- static uchar8 i=0; //1yá÷Ë÷òy
- static uchar8 j=0; //供电索引
- static uchar8 k=0; //串口发送计时
- TH0=0xF8;
- TL0=0xCC; //2ms
- //过流检测,同时躲过电机启动瞬间的尖峰电流
- OCBuf[0]=(OCBuf[0]<<1)|GL1;
- OCBuf[1]=(OCBuf[1]<<1)|GL2;
- if((OCBuf[0]==0x00)||(OCBuf[1]==0x00))
- {
- i++;
- OCBuf[0]=0xFF;
- OCBuf[1]=0xFF;
- if(i>=2)
- {
- i=0;
- OCflag=1;
- }
- }
- //供电状态检测
- PowSta=(PowSta<<1)|DcBat;
- j++;
- if(j>=8)
- {
- j=0;
- PowCNTR++;
- }
- //通信接收计时,TxFr_Succ为发送成功标志,RxFr_Succ为接收成功标志(置位表示接收成功,不置位不代表接收失败).RxFr_Fail接收失败标志,(置位表示接收失败,不置位不代表接收成功)
- if((TxFr_Succ)&&(!(RxFr_Succ))) //数据发送成功,但尚未接收到,开始计时
- {
- k++;
- if(k>=20) //计时40ms
- {
- k=0;
- RxFr_Fail=1; //接收失败,(从机不在线)
- TxFr_Succ=0; //
- }
-
- }
- else //计时清0,从数据发送成功开始计时,数据未发送成功,不计时,k清0,数据接收
- { //成功后,k清0.
- k=0;
- }
- }
- 定时器,UART,过流检测,供电状态检测,延时函数
- # define _TMR_UART_C
- # include "config.h"
- # include "tmr_uart.h"
- # include "main.h"
- //T0配置函数
- void ConfigTimer0()
- {
- TMOD&=0xF0;
- TMOD|=0x01;
- TF0=0;
- TH0=0xF8;
- TL0=0xCC;
- ET0=1;
- TR0=1;
- EA=1;
- }
- /*UART配置函数*/
- void ConfigUART()
- {
- SCON=0x50; //ÅäÖÃ′®¿úÎa·½ê½1£¬8λUART,2¨ìØÂê¿é±ä
- TMOD&=0x0F; //ÇåáãT1¿ØÖÆλ¡£
- TMOD|=0x20; //ÅäÖÃT1ÎaÄ£ê½2.
- TH1=0xFD;
- TL1=TH1; //2¨ìØÂê9600
- ES=1; //¿aÆô′®¿úÖD¶Ï
- ET1=0; //½ûÖ1T1ÖD¶Ï
- TR1=1; //Æô¶ˉT1
- }
- /*过流检测函数*/
- void OCProtect() //n*40ms½øDDò»′Î1yá÷ÅD¶Ï
- {
- if(OCflag) //ÖμÎa0x00,±íê¾òѾ-2úéú1yá÷¡£
- {
- ROE=1;RA3=1;RA2=1;RA1=1; //½«¿ØÖƼìμçÆ÷òy½Åè«2¿à-¸ß£¬êí·ÅËùóD¼ìμçÆ÷¡£
- while(1)
- {
- Buz=!Buz;
- DelayX50ms(5); //·äÃùÆ÷ÿ¸ô1SÏìò»′Ρ£
- }
- }
- }
- //供电状态检测函数
- void PowCheck(uchar8 t)
- {
- if(PowCNTR>=t)
- {
- PowCNTR=0;
- if(PowSta==0xFF)
- {
- TxdBuf[1]=0x12; //将供电状态变量赋给发送缓冲
- }
- else if(PowSta==0x00)
- {
- TxdBuf[1]=0x13; //将供电状态变量赋给发送缓冲
- }
- else;
- }
- }
- /*延时函数*/
- void DelayX50ms(uchar8 t) //@11.0592MHz
- {
- uchar8 i, j,k;
- i = 5;
- j = 121;
- for(k=0;k<t;k++)
- {
- do
- {
- while (--j);
- }
- while (--i);
- }
- }
- //延时函数
- void DelayX10us(uchar8 t)
- {
- do{
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- _nop_();
- }while(--t);
- }
- # define _ACTION_C
- # include "config.h"
- # include "action.h"
- # include "main.h"
- //串口数据解析函数
- void UartAction(uchar8 addr)
- {
- if(buf[0]!=addr) //ê×Ïèo˶ÔμØÖ·£¬2»êÇ′ó»úF1·¢à′μÄêy¾Y£¬Ö±½ó·μ»Ø
- {
- return;
- }
- switch(buf[1])
- {
- case 0x03:ReturnPos(addr);break;
- case 0x04:ROE=0;RA3=0;RA2=0;RA1=0; LedDisp(1); break; //C1PÎaμíμçƽ
- case 0x05:ROE=0;RA3=0;RA2=1;RA1=0; LedDisp(2); break; //C2PÏòí·Æ½òÆ
- case 0x06:ROE=1;RA3=0;RA2=1;RA1=0; LedDisp(5); break; //C5P±3°åéÏéy
- case 0x07:ROE=0;RA3=1;RA2=1;RA1=0; LedDisp(11);break; //1#Y6 é23μ
- case 0x08:ROE=0;RA3=0;RA2=1;RA1=1; LedDisp(7); break; //C2NÏò½ÅƽòÆ
- case 0x09:ROE=1;RA3=0;RA2=1;RA1=1; LedDisp(10);break; //C5N±3°åϽμ
- case 0x0A:ROE=0;RA3=0;RA2=0;RA1=1; LedDisp(6); break; //C1NϽμ
- case 0x0B:ROE=1;RA3=1;RA2=0;RA1=0; LedDisp(13);break; //2#Y4 Ñüéy
- case 0x0C:ROE=1;RA3=0;RA2=0;RA1=0; LedDisp(4); break; //C4P×óÇã
- case 0x0D:ROE=0;RA3=1;RA2=1;RA1=1; LedDisp(12);break; //1#Y7 Ëéé23μ
- case 0x0E:ROE=0;RA3=1;RA2=0;RA1=1; LedDisp(8); break; //C3Ní·½μ½Åéy
- case 0x0F:ROE=1;RA3=1;RA2=0;RA1=1; LedDisp(14);break; //2#Y5 Ñü½μ
- case 0x10:ROE=0;RA3=1;RA2=0;RA1=0; LedDisp(3); break; //C3Pí·éy½Å½μ
- case 0x11:ROE=1;RA3=0;RA2=0;RA1=1; LedDisp(9); break; //C4NóòÇã
- case 0xFF:ROE=1;RA3=1;RA2=1;RA1=1; LedDisp(19);break; //êí·ÅËùóD¼ìμçÆ÷
- default:ROE=1;RA3=1;RA2=1;RA1=1;Dis_Pin=0xFF;break;
- }
- }
- //LED显示函数
- void LedDisp(uchar8 temp)
- {
- switch(temp)
- {
- case 1: Dis_Pin=0x9F;break; //9F:1001 1111 ÏÔê¾1
- case 2: Dis_Pin=0x31;break; //31:1010 1110 ÏÔê¾2
- case 3: Dis_Pin=0x15;break; //15: ÏÔê¾3
- case 4: Dis_Pin=0x9C;break; // ÏÔê¾4
- case 5: Dis_Pin=0x54;break; // ÏÔê¾5
- case 6: Dis_Pin=0x8F;break; // ÏÔê¾1.
- case 7: Dis_Pin=0x21;break; // ÏÔê¾2.
- case 8: Dis_Pin=0x05;break; // ÏÔê¾3.
- case 9: Dis_Pin=0x8C;break; // ÏÔê¾4.
- case 10: Dis_Pin=0x44;break; // ÏÔê¾5.
- case 11: Dis_Pin=0x50;break; // ÏÔê¾6
- case 12: Dis_Pin=0x40;break; // ÏÔê¾6.
- case 13: Dis_Pin=0x1F;break; // ÏÔê¾7
- case 14: Dis_Pin=0x0F;break; // ÏÔê¾7.
- default: Dis_Pin=0x00;break;
- }
- }
- //复位函数
- void ReturnPos(uchar8 addr)
- {
- if(RW5==0)
- {
- ROE=1;RA3=0;RA2=1;RA1=0; LedDisp(5); //±3°åéÏéy
- while(RW5==0)
- {
- ReAction(addr);
- }
- }
- else if(RW5==1)
- {
- ROE=1;RA3=0;RA2=1;RA1=1; LedDisp(10); //±3°åϽμ
- while(RW5==1)
- {
- ReAction(addr);
- }
- }
- //×óóòÇãD±¸′λ
- if(RW4==0)
- {
- ROE=1;RA3=0;RA2=0;RA1=0; LedDisp(4); //×óÇã
- while(RW4==0)
- {
- ReAction(addr);
- }
- }
- else if(RW4==1)
- {
- ROE=1;RA3=0;RA2=0;RA1=1; LedDisp(9); //óòÇã
- while(RW4==1)
- {
- ReAction(addr);
- }
- }
- //Ç°oóÇãD±¸′λ
- if(RW3==0)
- {
- ROE=0;RA3=1;RA2=0;RA1=0; LedDisp(3); //Ç°Çã
- while(RW3==0)
- {
- ReAction(addr);
- }
- }
- else if(RW3==1)
- {
- ROE=0;RA3=1;RA2=0;RA1=1; LedDisp(8); //oóÇã
- while(RW3==1)
- {
- ReAction(addr);
- }
- }
- if(RW2==0)
- {
- ROE=0;RA3=0;RA2=1;RA1=0; LedDisp(2); //Ïòí·Æ½òÆ
- while(RW2==0)
- {
- ReAction(addr);
- }
- }
- else if(RW2==1)
- {
- ROE=0;RA3=0;RA2=1;RA1=0; LedDisp(7); //Ïò½ÅƽòÆ
- while(RW2==1)
- {
- ReAction(addr);
- }
- }
- if(RW1==0)
- {
- ROE=0;RA3=0;RA2=0;RA1=1; LedDisp(6); //Ïòí·Æ½òÆ
- while(RW1==0)
- {
- ReAction(addr);
- }
- }
- ROE=1;RA3=1;RA2=1;RA1=1; //1رռìμçÆ÷êä3ö¡£
- }
- //复位解析函数,复位期间,也要一直与从机进行通信,并解析数据.
- void ReAction(uchar8 addr)
- {
- UartSend(addr);
- switch(sl_select)
- {
- case 0:if(RxFr_Succ)
- {
- RxFr_Succ=0;
- UartReceive();
- if(buf[0]!=addr)
- {
- return;
- }
- if((buf[1]==0xFF)||(buf[1]==0x03))
- {
- sl_select++;
- }
- else
- break;
- }
- case 1:if(RxFr_Succ)
- {
- RxFr_Succ=0;
- UartReceive();
- if(buf[0]!=addr)
- {
- return;
- }
- if((buf[1]==0xFF)||(buf[1]==0x03))
- {
- sl_select--;
- }
- else
- break;
- }
- default:break;
- }
- }
复制代码
|