1、由于我和我的partner都用的WSL(Windows Subsystem for Linux),对于通信方面有一定的优化,在读取信号方面代码可以做到很简洁。
2、如果代码方面有问题或者想尝试安装一个WSL可以移步我的计算机系统专栏,里面有一篇文章有教学。其实安装挺简单的,半个小时就ok了,比虚拟机好得多。
3、先赞后看,养成习惯。
4、仅供参考,谨慎抄袭
一、实验目的
1、熟练使用Linux下io函数read、write和epoll等
2、熟练RS485串口的信号特点
三、实验过程
两个同学一人下载A板文件,一人下载B板文件
B板会将计算机通过USB 串口发送的数据,转发到RS485接口上。同时将RS485接口收到的数据,通过USB 串口转发到计算机上。我们接下来使用这个B板与自己的A板进行通信,读取A板的密码。
先将板子连接电脑,第一次我下载B程序,我的partner下载A程序。用示波器与板子标有485位置的两个孔相连,调整示波器参数,使得波形方便看清楚,单次触发,可以计算出A板的波特率。
这里计算出波特率是九千多那个档次(1除以一个稍微比100微秒大一点的数)
然后将示波器与B板相连,通过调节B板的摇杆,使得它与A板有相同的的波特率。
现在准备工作就算做完了,波特率相同就可以通信了。现在最好不要再动板子,以防再出什么问题。
用电脑上之前下载的STC-ISP可以读取A板的序列号:波特率调成用示波器算出来的那个波特率,打开串口助手就可以了。
下载B程序的就要在电脑上写程序来读取密码(注意在com.c里面要改波特率)。
#include
#include "com.h"
#include "com.c"
#include
int main(void)
{
//unsigned char tmp[15] = {0}; //用于存放读取出来的数据的缓冲区
int rl; //读取数据的长度(单位:字节)
fd = openSerial("/dev/ttyS4"); //打开串口,ttyUSB0是串口文件
if(fd < 0)
{
printf("open com fail!\n");
return 0;
}
EpollInit(fd); //初始化终端事件触发函数epoll,设置要监听的事件及相关参数等
unsigned char number[14] = {0xAA,0x55,0x02,0x00,0x02,0x00,0x00,0x08,0x00,0x01,0x00,0x03,0x00,0x03};
write(fd, number, sizeof(number));
unsigned char tmp[19] = {0};
unsigned char fill[6] = {0};
while(1)
{
int i;
//bzero(tmp,sizeof(tmp)); //把tmp对应的内存块的前sizeof(tmp)置零
rl = ComRead(tmp,18);//读取18个字节放到缓存
assert(rl > 6);
//打印读到的数据
printf("read_len = %d\n", rl);
tmp[rl] = '\0';
for(i = 0; i < rl; i++)
printf(" %02x", tmp[i]);
printf("\n\n");
for(i = 0; i < 6; i++)
{
if(i == 0)
fill[i] = 0xAA;
else if(i == 1)
fill[i] = 0x55;
else
fill[i] = tmp[(int)tmp[2]-3+i];
}
for(i = 0; i < 6; i++)
printf(" %02x", fill[i]);
printf("\n\n");
//unsigned char fill[6] = {0xaa, 0x55, 0xe4, 0xc3, 0x11, 0x7a};
bzero(tmp, 19);
if(write(fd, fill, 6) > 0)
printf("Write success\n");
bzero(fill, 6);
}
close(epid);
close(fd);
return 0;
}
curl “132.232.98.70:6363/check485?id=学号&v=序列号&s=密码”
回应OK表示正确,其它表示错误。例如,序列号是D9 01 49 8A ,学号是202201030303,回应的密码为 01 8A D9 49,那么上报结果命令为:
curl “132.232.98.70:6363/check485?id=202201030303&v=D901498A&s=018AD949”
这样就算成功一次了。再两个人交换一下,下载另一个程序,重复上述步骤就完成了此任务。
一、实验目的
1、熟练使用Linux下io函数read、write和epoll等
2、熟练处理流式通信数据
3、理解485总线的冲突问题
二、预备知识
RS485总线有两条线信号线,能够传输一个逻辑信号。计算机标准的UART串口有RX、TX收发两条线,因此能够同时进行数据的接收和发送。而RS485只有一个逻辑信号,因此同一时刻只能有一个主体进行数据发送(因此叫做半双工通信串口)。
单片机板上使用了一颗MAX485芯片作为标准UART接口向485接口转换的接口芯片。请同学们学习该芯片介绍和各引脚的功能。
如下图所示,单片机串口数据发送脚与MAX485的DI脚相连接。在发送数据前,单片机会将DE脚置为高电平,此时A、B引脚信号为所发送的单片机串口数据。
如果多个单片机将DE脚置为高电平,则A、B信号线同时被多个单片机板的MAX485芯片驱动,则会造成数据收发错误甚至损坏芯片。因此,多个单片机对485总线操作的时间控制至关重要。
四、实验过程
和上一个任务一样,分A,B两个程序,两个人每个人下一个程序,总共要做两遍,不同之处在于波特率是确定的,不用再拿示波器测量了。
1、下载程序后,A板单片机将使用1200波特率约每300ms发送一次自身序列号,格式为
0xAA 0x55 4字节序列号
还是用电脑上的STC-ISP波特率调为1200打开串口助手来获得序列号
2、通过B板串口向RS485总线写入自己的学号,格式为
0xAA 0x55 十二位学号数字。
例如学号20220110203,应该通过串口发送以下数据
AA 55 02 00 02 02 00 01 01 01 00 02 00 03
3、A板单片机接收到学号后会每300m发送第一串密码,密码长度为4字节。请将解析出该串密码并在150ms内原样发回给串口(否则会造成总线的冲突)。STC单品机收到返回后会继续发送下一串密码,请继续解析出该串密码并在150ms内原样发回给串口。以此往复,将收到的最后一串密码记录下来。
例如,收到以下密码串
AA 55 00 00 00 00 00 C9 34 3F 5D
其中AA 55为前导串,最后4个字节是密码。请将密码原样发回给串口。
AA 55 C9 34 3F 5D
通过写程序来不断获取密码,等到密码一直相同时中断程序,就能向系统发送数据了。
#include
#include "com.h"
#include "com.c"
#include
int main(void)
{
//unsigned char tmp[15] = {0}; //用于存放读取出来的数据的缓冲区
int rl; //读取数据的长度(单位:字节)
fd = openSerial("/dev/ttyS4"); //打开串口,ttyUSB0是串口文件
if(fd < 0)
{
printf("open com fail!\n");
return 0;
}
EpollInit(fd); //初始化终端事件触发函数epoll,设置要监听的事件及相关参数等
unsigned char number[14] = {0xAA,0x55,0x02,0x00,0x02,0x00,0x00,0x08,0x00,0x01,0x00,0x03,0x00,0x03};
write(fd, number, sizeof(number));
unsigned char tmp[19] = {0};
unsigned char fill[6] = {0};
while(1)
{
int i;
//bzero(tmp,sizeof(tmp)); //把tmp对应的内存块的前sizeof(tmp)置零
rl = ComRead(tmp,18);//读取18个字节放到缓存
//打印读到的数据
printf("read_len = %d\n", rl);
tmp[rl] = '\0';
for(i = 0; i < rl; i++)
printf(" %02x", tmp[i]);
printf("\n\n");
/*
for(i = tmp[2] - 0x30 + 1; i < tmp[2] - 0x30 + 5; i++)
printf(" %02x", tmp[i]);
printf("\n\n");
*/
for(i = 0; i < 6; i++)
{
if(i == 0)
fill[i] = 0xAA;
else if(i == 1)
fill[i] = 0x55;
else
fill[i] = tmp[rl-6+i];
}
for(i = 0; i < 6; i++)
printf(" %02x", fill[i]);
printf("\n\n");
//unsigned char fill[6] = {0xaa, 0x55, 0xe4, 0xc3, 0x11, 0x7a};
bzero(tmp, 19);
if(write(fd, fill, 6) > 0)
printf("Write success\n");
bzero(fill, 6);
}
close(epid);
close(fd);
return 0;
}
4、将学号、序列号、最后一串密码发送到课程后台。上送命令语法为
curl “132.232.98.70:6363/check485Secret?id=学号&v=序列号&s=密码”
例如,序列号是2C9363F5E,学号是202201110203,最后一串密码为51ED8D3A,那么上报结果命令为:
curl “132.232.98.70:6363/check485Secret?id=202201110203&v=2C9363F5E&s=51ED8D3A”
后台返回的数字表示该密码的编号,返回DUP表示该序列号已经被其它同学使用,请更换电路板重新取得密码。