既然是车规级MCU,那当然是应用在汽车领域了,而CAN和LIN通信,是汽车常见的通信方式。今天先实验LIN。
一、硬件准备
如果只是看看总线波形,只有一块AC78013开发板就可以了,作为LIN主机,硬件电路也不必修改。
而我恰好还有一块AC7811通用开发板,于是就用7811做主机。(PS:我的AC7811通用开发板,是杰发一位代理商赠送的。看来,代理商的信息还是要认真回复的,万一有好事降临呢)
而AC78013开发板做从机,需要把板子上的电路稍稍调整一下:
然后用2根导线,连接主机、从机的LIN接口(注意,2条线分别是LIN线和GND,不要接反)
要准备AC220转DC12V的电源适配器2只:
二、软件准备
官方提供的LIN协议应用例程,在官网“AC7801x模块应用例程”《ac7801xmoduleapplicationnotes20200426.rar》的UART目录下。
该例程略有不完善,请按以下步骤修改:
1、MDK打开UART_LIN工程,把已有的main.c添加到工程user项中去:
2、点击MDK工具栏上的绿色菱形按钮,打开Manage Run-Time Environment窗口,勾选Device下面的TIMER(因为协议用到了一个定时器):
3、OK,现在可以编译通过了
4、还可以打开c文件,在菜单Edit-->Config-->Editor-->Encoding项,改成GB2312,这样可以使用中文注释了。
AC781x的LIN例程,在官网“AC781x Demo工程代码(KEIL和IAR)”《AC781x范例代码.rar》的Boards目录下。
三、分析LIN代码
论坛发布的试用报告贴子,极少有体验LIN的。
或许有的坛友对LIN不太熟悉。那么在下就把官方代码稍加分析,算是对新手的一个入门引导,高手请不要反感。
LIN协议不算复杂,使用起来也很简单。如下图,官方例程的main.c里,先是定义为主机角色:
uint8_t mode = MASTER_MODE;
然后运行到
LIN_InitLin(MASTER_MODE, 0, 19200);
这句之后,LIN主机已启动并开始调度了。
LIN_InitLin函数有3个参数,其中第1个是LIN设备模式(主/从),第3个是波特率,而第2个参数,实际上赋值给了一个全局变量:
uint8_t g_schTblIdx;
它的含义是,指定使用列表中的哪个进度表。
所谓列表,即:
SCHEDULE_TBL g_scheduleTable[] =
{
{4, &g_frameTable1[0]},
{4, &g_frameTable2[0]},
{4, &g_frameTable3[0]},
{4, &g_frameTable4[0]},
{4, &g_frameTable5[0]},
{4, &g_frameTable6[0]},
};
比如,如果g_schTblIdx==1,就是使用g_scheduleTable里的这个进度表:
{4, &g_frameTable2[0]}//这个进度表有4个帧,内容如下:
///< Master send header and receive data
FRAME_ID_TBL g_frameTable2[] =
{
{0x01, 1, 0, 1, 60, &g_data1[0]},//第1帧
{0x02, 0, 0, 2, 60, &g_data2[0]},//第2帧
{0x03, 1, 0, 4, 60, &g_data4[0]},//第3帧
{0x04, 0, 0, 8, 60, &g_data8[0]},//第4帧
};
如定义所示,每一帧有6个字段,分别是:帧ID、数据方向、校验类型、数据长度、帧窗口宽度(帧时隙)、数据地址。
数据方向==1,则表明本设备向总线上发送数据地址指向的数据;
数据方向==0,则表明本设备从总线上接收数据存放在数据地址处。
帧窗口宽度(帧时隙),可以结合下图理解(如定义所示,假设为60ms):
LIN_InitLin函数首先启动UART工作,然后(主机)又启动一个TIMER,然后就定时循环执行这个进度表里的4个帧。
LIN总线就工作了。
下面把官方例程稍稍修改一下,以便更加清晰地看懂主机从机的工作。
我把示波器采集的波形截图,在图上做了标记。
在主机端,我把数据全部初始化为0x55:
uint8_t g_data1[1] = {0x55};
uint8_t g_data2[2] = {0x55, 0x55};
uint8_t g_data4[4] = {0x55, 0x55, 0x55, 0x55};
uint8_t g_data8[8] = {0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55, 0x55};
主机使用以下进度表:
FRAME_ID_TBL g_frameTable2[] =
{
{0x01, 1, 0, 1, 20, &g_data1[0]},//这一帧由主机发出
{0x02, 0, 0, 2, 20, &g_data2[0]},//这一帧由从机发来
{0x03, 1, 0, 4, 20, &g_data4[0]},//这一帧由主机发出
{0x04, 0, 0, 8, 20, &g_data8[0]},//这一帧由从机发来
};
在从机端,数据全部初始化为0xFF、0x00、0xF0等特征:
uint8_t g_data1[1] = {0xF0};
uint8_t g_data2[2] = {0xF0, 0xF0};
uint8_t g_data4[4] = {0xFF, 0x00, 0xFF, 0x00};
uint8_t g_data8[8] = {0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00};
从机使用以下进度表:
FRAME_ID_TBL g_frameTable4[] =
{
{0x01, 0, 0, 1, 20, &g_data1[0]},//这一帧数据由主机发来
{0x02, 1, 0, 2, 20, &g_data2[0]},//这一帧数据由从机发出
{0x03, 0, 0, 4, 20, &g_data4[0]},//这一帧数据由主机发来
{0x04, 1, 0, 8, 20, &g_data8[0]},//这一帧数据由从机发出
};
注意,主机和从机的进度表,数据传送方向完全相反;为便于缩放观察,帧时隙全部改成了20ms。
于是我期望的结果是:等LIN运行后,主从机数据全部变成:
uint8_t g_data1[1] = {0x55};//由主机传送到从机
uint8_t g_data2[2] = {0xF0, 0xF0};//由从机传送到主机
uint8_t g_data4[4] = {0x55, 0x55, 0x55, 0x55};//由主机传送到从机
uint8_t g_data8[8] = {0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00, 0xFF, 0x00};//由从机传送到主机
四、运行后在总线上采集的示波器图像
4帧,循环执行,帧时隙20ms:
这是第1帧,数据0x55从主机到从机,字节低位在前高位在后,即10101010:
第2帧的数据2个字节,是从机发送到主机,注意低位在前,高位在后(后不赘述了):
第3帧和第4帧:
官方代码中,有一个 《AC7801x UART模块应用笔记.pdf》有参考价值。
本贴附件中,在下上传了一个《RENESAS瑞萨LIN入门书.pdf》是公认的好资料。
实验容易,写报告不易!很辛苦的感觉。
如果你觉得看完我费力做的图片,有所收获,劳驾动手回贴一下,可以下载隐藏附件中的源码和文档。
|