一、功能 主体功能:三台单片机之间两两互相通信,为此,我们将其拟人化,以三个主人公Jack、Carl、Lily之间的交流来演示。具体过程如下: ①初始状态(从上至下分别为Jack、Lily、Carl):
②Lily编辑“HELLO!”的字符串准备发送给Jack:
③Lily按下发送后Jack的接收结果: ④Carl编辑“Hi!”发送给Lily同时Lily接收:
⑤Jack编辑“HOW ARE U”发送给Carl同时Carl接收:
⑥特殊情况:当传送过来的数据经奇偶校验出错后给出报错提示:
二、 网络的设计物理层: 传输介质: 采用两条杜邦线连接单片机的两个io口,一个io口定时变换高低电平输出数据,另一个io口定时检测电平高低来读取数据,实现了全双工通讯。 每台单片机都有2对(4个)io口可以发送接受数据,这为多台机器组成网络提供了基础。 多台单片机连接方式: 我们用3台单片机组成了一条线似的结构,实际上这个网络还可以在边上扩展延长,这个网络中不存在主机,每台机器都是平等的。 每台单片机收到信息后,都会将信息从另一对io口发出。每台单片机发送给信息时候,也会将信息从两对io口同时发出,因此一旦有信息发送,信息会传播到整个网络。 编码技术:采用不归零电平编码方式(NRZ-L),高电平代表1,低电平代表0,每一bit数据的持续时间是31.108ms。由于每bit的持续时间决定了传输速率,因此传输数据可以通过简单修改宏定义来实现,不过随着传输速率的提高,出错率会增加。
传输协议:采用异步传输方式,每次传输一个bit。传输数据的格式如下
数据链路层: 成帧技术采用的是字符计数成帧技术,首部的高4位代表接下来要发送的字符数 数据是由谁发出,数据发给谁: 这部分功能也是由字符首部来完成,首部的结构如下: 如上图所示,这个首部代表接下来还要发送2个字符,目标地址是0,源地址是1。
三、 部分代码3台单片机的代码都是相同的,连接外部按键和显示器的引脚差别可以通过修改宏定义来适配。因此只列出一台单片机的代码 1. main.h- #ifndef _main_h_
- #define _main_h_
-
- #define MYNAME "Jack"
- #define NAME_NUM 2
- #define BUTTON_IO P3
- #define PRESS_LEFT 0x0E//k30
- #define PRESS_RIGHT 0x0D //k31
- #define CHANGE 0x0B //k32
- #define SEND 0x07 //k33
- #define PRESS_TIME 5000//按键消去抖动时间
- #define ASCII 32
- #define GPIO_KEY P3 //独立键盘用P1口
- //carl Lily Jack Lisa
-
- void send(unsigned char* TxArray,unsigned char sendTo);
- void receive(void);
- void errorFun(unsigned char a);
- unsigned char Key_Scan();
- Show_Name(int sendTo); //显示名字
- #endif
复制代码
2. 1602LCD.h#ifndef _1602LCD_h_ #define _1602LCD_h_ sbit RS = P2 ^ 6; //寄存器选择位,将RS位定义为P2.0引脚 sbit RW = P2 ^ 5; //读写选择位,将RW位定义为P2.1引脚 sbit E = P2 ^ 7; //使能信号位,将E位定义为P2.2引脚 sbit BF = P0 ^ 7; //忙碌标志位,,将BF位定义为P0.7引脚
bit BusyTest(void); void Write_com(unsigned char dictate); void WriteAddress(unsigned char x); void WriteData(unsigned char y); void LcdInt(void);
#endif
3. main.c- #include // 包含51单片机寄存器定义的头文件
- #include"1602LCD.h"
- #include"myParity.h"
- #include"main.h"
-
- sbit TxPort = P1 ^ 0;
- sbit RxPort = P1 ^ 1;
- sbit TxPort2 = P1 ^ 2;
- sbit RxPort2 = P1 ^ 3;
- #define TIMEHIGH 0xD0;
- #define TIMELOW 0x00;
- unsigned char i;
- unsigned int TxData;
- unsigned char Ti;
- unsigned int RxData;
- unsigned char Ri;
- unsigned char code tab[] = { 0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8, 0x80, 0x90 }; //共阳数码管 0-9
-
-
- /**************************************************************
- 函数功能:主函数
- **************************************************************/
- void main(void)
- {
- unsigned char TxArray[13] = {0,0, 0, 0, 0, 0, 0, 0, 0, 0,0,0,0 };
- unsigned char position = 0;
- unsigned char sendTo = 0;
-
- unsigned char keyNum; //获取键值
- char a; //循环变量
- char flag=0;
- RxData = 0;
- TxData = 0;
- Ti = 0;
- Ri = 0;
- i = 0;
- P1 = 0xff;
- P3=0xff;
- P3=0xff;
-
- EA = 1; //开总中断
- ET0 = 1; //定时器T0中断允许
- TMOD = 0x01; //使用定时器T0的模式1
- TH0 = TIMEHIGH;
- TL0 = TIMELOW;
- TR0 = 1; //启动定时器T0
- LcdInt();
- delay(1000);
-
- Write_com(0x01);//清显示:清屏幕指令
- WriteAddress(0x40);
- WriteAddress(0x40);
- for(a=0;a<10;a++)
- {
- WriteAddress(0x40+a);
- WriteData(ASCII+TxArray[a]);
- }
- WriteAddress(0x4A);
- WriteData('-');
- WriteAddress(0x4B);
- WriteData('>');
- WriteAddress(0x40);
- sendTo=NAME_NUM+1;
- if(NAME_NUM>1)
- sendTo=0;
- Show_Name(sendTo);
- WriteAddress(0x40);
- while (1)//无限循环等待中断
- {
- keyNum = Key_Scan(); //扫描键盘
- switch (keyNum&0x0F)
- {
- case(PRESS_LEFT) :
- if( (position>=0) && (position<10) )
- {
- WriteAddress(0x40+position);
- if(TxArray[position]<32)
- TxArray[position]=128;
- else
- TxArray[position]--;
- WriteData(TxArray[position]);
- WriteAddress(0x40+position);
- }
- else if( (position==10) || (position==11) )
- {
- for(a=0;a<10;a++)
- {
- TxArray[a]=0;
- WriteAddress(0x40+a);
- WriteData(0);
- }
- WriteAddress(0x40);
- position=0;
- }
- else
- {
- if(sendTo>0)
- {
- sendTo--;
- }
- else
- {
- sendTo=3;
- }
- Show_Name(sendTo);
- }
- break;
- case(PRESS_RIGHT) :
- if( (position>=0) && (position<10) )
- {
- WriteAddress(0x40+position);
- if(TxArray[position]<32)
- TxArray[position]=65;
- else if(TxArray[position]>128)
- TxArray[position]=32;
- else
- TxArray[position]++;
- WriteData(TxArray[position]);
- WriteAddress(0x40+position);
- }
- else if( (position==10) || (position==11) )
- {
- for(a=0;a<10;a++)
- {
- TxArray[a]=0;
- WriteAddress(0x40+a);
- WriteData(ASCII);
- }
- WriteAddress(0x40);
- position=0;
- }
- else
- {
- if(sendTo<3)
- {
- sendTo++;
- }
- else
- {
- sendTo=0;
- }
- Show_Name(sendTo);
- }
- break;
- case(CHANGE) :
- if(position<12)
- {
- position++;
- }
- else
- {
- position=0;
- }
- WriteAddress(0x40+position);
- break;
- case(SEND) :
- flag=0;
- for(a=9;a>=0;a--)
- {
- if(flag==1&&TxArray[a]==0)
- TxArray[a]=32;
- else if(TxArray[a]!=0)
- flag=1;
- }
- send(TxArray,sendTo);
- break;
- default:
- break;
- }
- receive();
- }
-
- }
-
- Show_Name(int sendTo)
- {
- if(sendTo==0)
- {
- WriteAddress(0x4C);
- WriteData('C');
- WriteAddress(0x4D);
- WriteData('a');
- WriteAddress(0x4E);
- WriteData('r');
- WriteAddress(0x4F);
- WriteData('l');
- WriteAddress(0x4C);
- }
- else if(sendTo==1)
- {
- WriteAddress(0x4C);
- WriteData('L');
- WriteAddress(0x4D);
- WriteData('i');
- WriteAddress(0x4E);
- WriteData('l');
- WriteAddress(0x4F);
- WriteData('y');
- WriteAddress(0x4C);
- }
- else if(sendTo==2)
- {
- WriteAddress(0x4C);
- WriteData('J');
- WriteAddress(0x4D);
- WriteData('a');
- WriteAddress(0x4E);
- WriteData('c');
- WriteAddress(0x4F);
- WriteData('k');
- WriteAddress(0x4C);
- }
- else
- {
- WriteAddress(0x4C);
- WriteData('L');
- WriteAddress(0x4D);
- WriteData('i');
- WriteAddress(0x4E);
- WriteData('s');
- WriteAddress(0x4F);
- WriteData('a');
- WriteAddress(0x4C);
- }
- }
- /*******************************************************************************
- * 函 数 名 : Key_Scan()
- * 函数功能 : 扫描键盘
- * 输 入 : 无
- * 输 出 : 读取到的键值
- *******************************************************************************/
-
- unsigned char Key_Scan()
- {
- unsigned char keyValue = 0 , i; //保存键值
-
- //--检测按键1--//
- if (GPIO_KEY != 0xFF) //检测按键是否按下
- {
- delay(PRESS_TIME); //消除抖动
-
- if (GPIO_KEY != 0xFF) //再次检测按键是否按下
- {
- keyValue = GPIO_KEY;
- /* i = 0;
- while ((i<50) && (GPIO_KEY != 0xFF)) //检测按键是否松开
- {
- delay(PRESS_TIME);
- i++;
- } */
- }
- }
-
- return keyValue; //将读取到键值的值返回
- }
-
- /**************************************************************
- 函数功能:定时器T0的中断服务程序
- **************************************************************/
- void Time0(void) interrupt 1 using 0 //“interrupt”声明函数为中断服务函数
- //其后的1为定时器T0的中断编号;0表示使用第0组工作寄存器
- {
- bit RxTemp;
- /*发送数据*/
- if ((TxData & 0x01) == 1)
- {
- if (Ti == 9)
- {
- TxPort = (bit)(TxData & 0x8000);
- TxPort2 = (bit)(TxData & 0x8000);
- Ti = 0;
- TxData = TxData & 0xfffe;
- }
- else
- {
- TxPort = (bit)(TxData & 0x8000);
- TxPort2 = (bit)(TxData & 0x8000);
- TxData <<= 1;
- TxData = TxData - 1;
- Ti++;
- }
- }
- else
- {
- TxPort = 1;
- TxPort2 = 1;
- }
- /*发送数据结束*/
-
- /*接收数据*/
- RxTemp=RxPort&RxPort2;
- if ((RxData & 0x8000) == 0x8000)//S1==1?
- {
- if (Ri != 8)
- {
- Ri++;
- RxData <<= 1;
- RxData = RxData | 0x8000;//S1置1
- RxData = RxData | (unsigned int)RxTemp;
- }
- else
- {
- RxData <<= 1;
- RxData = RxData | (unsigned int)RxTemp;
- Ri = 0;
- RxData = RxData & 0x7fff;//S1置0
- RxData = RxData | 0x4000;//S2置2
- }
- }
- else
- {
- if (RxTemp == 0)
- {
- if ((RxData & 0x4000) == 0)//S2==0?
- {
- RxData = RxData | 0x8000;//S1置1
- }
- else
- {
- errorFun(1);
- }
- }
- }
- if(RxPort==0)
- TxPort2=0;
- if(RxPort2==0)
- TxPort=0;
- /*接收数据结束*/
- TH0 = TIMEHIGH;
- TL0 = TIMELOW;
- }
-
- void errorFun(unsigned char a)
- {
- char i,s[]="Error";
- WriteAddress(0x00);
- for(i=0;i<16;i++)
- {
- WriteData(32);
- }
-
- WriteAddress(0x00);
- i=0;
- while(s[i]!=0)
- {
- WriteData(s[i]);
- i++;
- delay(100);
- }
- WriteData('0'+a);
- while(1);
- }
-
- void send(unsigned char* TxArray,unsigned char sendTo)
- {
- unsigned char Tcount=0,i=0,TxD=0;
- while (TxArray[Tcount] != 0)
- {
- Tcount++;
- }
- TxD |= Tcount;
- TxD<<=4;
- sendTo <<= 2;
- TxD |= sendTo;
- TxD |= NAME_NUM;
- while ((TxData & 0x0001) == 0x0001)//没发完
- ;
- TxData = calculateTxData(TxD);
- for (i = 0; i < Tcount; i++)
- {
- while ((TxData & 0x0001) == 0x0001)//没发完
- ;
- TxData = calculateTxData(TxArray[i]);
- }
- }
-
- void receive(void)
- {
- unsigned char RxArray[13] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
- unsigned char Rcount = 0, j = 0, sendTo = 0,temp=0;
- if ((RxData & 0x4000) == 0x4000)//S2==1,数据待读取
- {
- RxArray[0] = checkRxData();
- Rcount=RxArray[0] & 0xf0;
- Rcount>>=4;
- for (j = 1; j < Rcount+1; j++)
- {
- while ((RxData & 0x4000) == 0x0000)//没有数据读取
- ;
- RxArray[j] = checkRxData();
- }
- sendTo =RxArray[0] & 0x0c;
- sendTo>>=2;
- if (sendTo != NAME_NUM)
- ;//send(RxArray + 1, sendTo);
- else
- {
- WriteAddress(0x00);
- switch (RxArray[0] & 0x03)
- {
- case 0:
- WriteData('C');
- WriteData('a');
- WriteData('r');
- WriteData('l');
- break;
- case 1:
- WriteData('L');
- WriteData('i');
- WriteData('l');
- WriteData('y');
- break;
- case 2:
- WriteData('J');
- WriteData('a');
- WriteData('c');
- WriteData('k');
- break;
- case 3:
- WriteData('L');
- WriteData('i');
- WriteData('s');
- WriteData('a');
- break;
- }
- WriteData(':');
- WriteData(32);
- WriteData(32);
- WriteData(32);
- WriteData(32);
- WriteData(32);
- WriteData(32);
- WriteData(32);
- WriteData(32);
- WriteData(32);
- WriteData(32);
- WriteData(32);
- WriteAddress(0x05);
- for (j = 1; j < Rcount + 1;j++)
- WriteData(RxArray[j]);
- }
- }
- }
- 4. parity.h
- #include // 包含51单片机寄存器定义的头文件
- #include"myparity.h"
- #include"main.h"
- extern unsigned int RxData;
- //--定义全局变量--//
- unsigned char code DIG_PLACE[8] = {
- 0xfe, 0xfd, 0xfb, 0xf7, 0xef, 0xdf, 0xbf, 0x7f };//位选控制 查表的方法控制
- unsigned char code DIG_CODE[17] = {
- 0x50, 0x5c, 0x50, 0x50, 0x79 };
- //Error的显示码
- unsigned char DisplayData[8];
- //用来存放要显示的8位数的值
-
- /*来自安驰的代码如下*/
- unsigned char checkRxData()
- {
- unsigned int a = 1; //用于移位后与运算,即为0000 0001
- int i;
- int UsefulData = RxData;
- int bin[9] = { 0 }; //用于记录Rxdata转化为二进制后的数值
- int num1 = 0; //用于记录Rxdata中1的个数
-
- UsefulData = UsefulData >> 1; //先右移一位再与运算提取
- UsefulData = UsefulData & 255; //出原int型数据中有效的8位
-
- for (i = 0; i<9; i++)
- {
- bin[i] = RxData&a;
- RxData = RxData >> 1; //右移一位
- }
- for (i = 0; i<9; i++)
- {
- if (bin[i] == 1)
- {
- num1++;
- }
- }
- if (num1 % 2 == 0)
- {
- errorFun(2);//奇偶校验错error2
- }
- return (char)UsefulData;
- }
-
- unsigned int calculateTxData(unsigned char UsefulData)
- {
- unsigned int CutData;
- unsigned int FinalData;
- int flag = 0; //判断1的个数
- int bin[8] = { 0 };
- int num1 = 0;
- int num = 0;
- int i;
- CutData = (int)UsefulData;
- num = (int)UsefulData;
- for (i = 0; i<8; i++)
- {
- bin[i] = CutData & 1;
- CutData = CutData >> 1; //右移一位
- }
- for (i = 0; i<8; i++)
- {
- if (bin[i] == 1)
- ……………………
- …………限于本文篇幅 余下代码请从51黑下载附件…………
复制代码
详细内容见附件:
多台单片机间网络的实现.docx
(1.95 MB, 下载次数: 81)
|