模板: RS485 CAN Shield for use
来自Waveshare Wiki
准备工作
- RS485 CAN Shield 模块两个
- STM32 开发板两个(本手册用的是微雪电子的 Xnucleo 开发板,主控芯片是 STM32F103R)
- 杜邦线若干
跳线说明
- D14(PB_9)、D15(PB_8)分别作为默认 CAN 的发送端和接收端。
注:PB_9,PB_8 作为 STM32 CAN1 管脚时编程需打开管脚重映射。
GPIO_PinRemapConfig(GPIO_Remap1_CAN1, ENABLE);
- D7(PA_8)是 RS485 的发送接收使能端,高电平时为发送状态,低电平时为接收状态。
- D8(PA_9)、D2(PA_10)和 D0(PA_2)、D1(PA_3)分别是 UART1 和 UART2 的发送端和接收端。可
- 通过 485 RXD/TXD JMP 跳线帽选择 UART1 或 UART2 作为 RS485 的输出输入端。
注:Xnucleo 默认 PA_2、PA_3 作为串口转 USB 端口。若要用 D0、D1 作为 RS485 的串口,则还需变换 Xnucleo 中 JP4 相应跳线。用跳线帽将 1、3 管脚短接,2、4 管脚短接。Xuncleo原理图中 JP4 串口跳线如下图所示:

- 模块间通信,CAN 端口的 H,L 分别和另一个模块的 CAN 端口 H,L 对接。RS485 端口的 A,B 分别和另一个模块的 RS485 端口 A,B 对接。
硬件连接
| Shield | STM32 | 功能 |
| VCC | 3.3V | 电源输入 |
| GND | GND | 电源地 |
| D2 | PA10 | RS485接收端 |
| D8 | PA9 | RS485发送端 |
| D7 | PA8 | RS485 发送接收使能端 |
| D14 | PB9 | CAN发送端 |
| D15 | PB8 | CAN接收端 |
D0、D1 将信息输出到 PC 端的串口。
软件工作原理
本测试程序采用 mbed 框架+STM32 库函数的形式,分为发送程序和接收程序两个程序。
CAN:
CAN 驱动程序采用 STM32 库函数编写,封装在 CAN.cpp 和 CAN.h 两个文件中。程序开始调用 CAN
初始化函数 CAN_Config()配置相关寄存器。
发送程序将要发送的数据保存在发送邮箱(TxMessage)中,再调用驱动函数
CAN_Transmit(CAN1, &TxMessage)发送出去。
而接收程序侧调用 CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);将接收到的数据保存
在接收邮箱(RxMessage)中。
RS485:
发送端程序控制 RS485_E 为高电平,使 RS485 处于发送状态,通过 RS485.printf 函数让数据
通过 RS485 串口发送出去。而接收程序则开启接收中断,程序控制 RS485_E 为低电平,使 RS485
处于接收状态,中断服务函数通过 RS485.scanf 扫描接收到的数据。
代码简介
发送端程序说明
/*CAN:程序开始调用 CAN 初始化函数,配置相关寄存器。CAN 通信侧建立一个发送邮箱 TXMsg,
将要发送的数据保存在邮箱中,再调用驱动函数发送出去。
RS485:控制 RS485_E 为高电平,使 RS485 处于发送状态,通过连接到 RS485 的串口将数据发送
出去。*/
#include "mbed.h"
#include "CAN.h"
Serial pc(D1,D0); //serial print message
Serial RS485(D8, D2); //RS485_TX RS485_RX
DigitalOut RS485_E(D7); //RS485_E
CanTxMsg TxMessage;
uint8_t TransmitMailbox = 0;
int i =0,j=0;
int main() {
CAN_Config();//CAN initialize
RS485_E = 1;//The RS485 transmission status was enabled
/* TxMessage */ //Set the mailbox data to be sent
TxMessage.StdId = 0x10;
TxMessage.ExtId = 0x1234;
TxMessage.RTR=CAN_RTR_DATA;
TxMessage.IDE=CAN_ID_STD;
TxMessage.DLC=8;
TxMessage.Data[0] = 'C';
TxMessage.Data[1] = 'A';
TxMessage.Data[2] = 'N';
TxMessage.Data[3] = ' ';
TxMessage.Data[4] = 'T';
TxMessage.Data[5] = 'e';
TxMessage.Data[6] = 's';
TxMessage.Data[7] = 't';
pc.printf( "**** This is a RS485_CAN_Shield Send test program
****\r\n");
while(1) {
RS485.printf("ncounter=%d ",j);//RS485 Transmit Data
wait(1);
TransmitMailbox = CAN_Transmit(CAN1, &TxMessage);//CAN Transmit Data
i = 0;
while((CAN_TransmitStatus(CAN1, TransmitMailbox) != CANTXOK) &&
(i != 0xFFF)){
i++;
}
if(i == 0xFFF){
pc.printf("\r\can send fail\r\n");//Failed to send the packet due to timeout. Procedure
}
else{
pc.printf("\r\nCAN send TxMessage successfully \r\n");
//send successful
}
pc.printf("\r\nRS485 send: counter=%d\r\n",j++);//Print sending content
pc.printf("The CAN TxMsg: %s\r\n",TxMessage.Data);
wait(1);
}
}
接收端程序说明
/*CAN:程序开始调用 CAN 初始化函数,配置相关寄存器。接收端查询 FIFO 中是否有数据,有的
话,则将接收到的数据保存到接收邮箱 RxMessage 中,再通过串口打印出来。
RS485:使能 RS485 接收中断函数,控制 RS485_E 为低电平,使 RS485 处于接收状态,中断服务
函数通过 RS485.scanf 扫描接收到的数据。*/
#include "mbed.h"
#include "CAN.h"
Serial pc(D1,D0); //serial print message
Serial RS485(D8, D2); //RS485_TX RS485_RX
DigitalOut RS485_E(D7); //RS485_E
CanRxMsg RxMessage; //RxMessage
char s[1024];
void callback()//RS485 Receive interrupt handler function
{// Note: you need to actually read from the serial to clear the RX interrupt
RS485.scanf("%s",s);//Save received data
pc.printf("\r\nRS485 Receive:%s \r\n",s);//Print receiving information
}
int main() {
CAN_Config();//CAN initialize
RS485.attach(&callback);//Enable RS485 receiving interruption
RS485_E = 0;//The receiving status was enabled
pc.printf( "**** This is a can receive test program ****\r\n");
while(1) {
while(CAN_MessagePending(CAN1, CAN_FIFO0) < 1)//Waiting for data to arrive
{
}
CAN_Receive(CAN1, CAN_FIFO0, &RxMessage);//CAN Receive Data
pc.printf("The CAN RxMsg: %s\r\n",RxMessage.Data);//Print received data
}
}


