STM32F103C8T6配置CAN通信:仅供自学参考
前期准备
硬件:
两个STM32F103C8T6 两个can模块 usb转TTL
软件:
cubeide
生成工程
打开Cubeide我用的是1.9.0版本
首先新建一个项目
之后选择MCU型号STM32F103C8T6
最后输入项目名称点击完成
项目新建完成后开始配置引脚
先配置时钟
1.
2.
3.
然后回到引脚配置界面配置下载方式
最后配置CAN 和UART
uart选择好后其他默认配置就可以
CAN
CAN波特率计算方法
波特率=APB1 peripheral clocks/prescaler/(TQ1+TQ2+SJW)
以STM32F103C8T6为例
如设置波特率为500K
36M/4/(9+8+1)=500K
为了方便看程序是否可以正常运行配置PC13(LED引脚)
配置好后选择Project Manager
生成相应的.C文件
配置好后即可生成代码
对项目属性进行设置
中文乱码情况
右键项目->属性
文本编码选择GBK格式
点击应用并关闭
浮点型不能输出的情况
开始编写代码
首先先对串口printf重映射编写
打开usart.c文件
在这个位置添加此代码
#include "stdio.h"
#ifdef __GNUC__
#define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
#define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
PUTCHAR_PROTOTYPE
{
HAL_UART_Transmit(&huart1 , (uint8_t *)&ch, 1, 0xFFFF);
return ch;
}
main.c添加此代码
printf("asd\r\n");
printf("汉字测试\r\n");
printf("整型测试%d\r\n",123);
printf("浮点型测试%f\r\n",12.333);
HAL_Delay(1000);
编译工程并下载 打开串口助手可以看到能正常输出
接下来对CAN进行配置
can过滤器代码
过滤器暂时先不过滤 全部接收
在CAN.C /* USER CODE BEGIN 0 */下添加此代码
#include "usart.h"
extern CAN_TxHeaderTypeDef Can_Tx;
extern uint8_t Txdata[8];
void CAN_User_Init(CAN_HandleTypeDef* hcan ) //用户初始化函数
{
CAN_FilterTypeDef sFilterConfig;
HAL_StatusTypeDef HAL_Status;
sFilterConfig.FilterActivation = ENABLE; //激活过滤器
sFilterConfig.FilterBank = 1; //过滤器1
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //设为掩码模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //设为32位
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0; //接收到的报文放入到FIFO0中
sFilterConfig.FilterIdHigh = 0; //基本ID放入到STID中
sFilterConfig.FilterIdLow = 0;
sFilterConfig.FilterMaskIdHigh =0;
sFilterConfig.FilterMaskIdLow =0;
sFilterConfig.SlaveStartFilterBank = 0;
HAL_Status=HAL_CAN_ConfigFilter(hcan, &sFilterConfig);
HAL_Status=HAL_CAN_Start(hcan); //开启CAN
if(HAL_Status!=HAL_OK){
// printf("开启CAN失败\r\n");
}
HAL_Status=HAL_CAN_ActivateNotification(hcan,CAN_IT_RX_FIFO0_MSG_PENDING);
if(HAL_Status!=HAL_OK){
//printf("开启挂起中段允许失败\r\n");
}
}
/*
发送命令函数
StdId 标准帧ID
ExtId 扩展帧ID 当标志位 IDE为CAN_ID_STD时 扩展帧无效
IDE 扩展帧标志位 CAN_ID_STD为标准ID CAN_ID_EXT为使用扩展ID
RTR 0(CAN_RTR_DATA)为数据帧 1(CAN_RTR_REMOTE)为远程帧
DLC 数据长度
*/
void sendOrder(uint32_t StdId,uint32_t ExtId,uint8_t IDE,uint8_t RTR, uint8_t DLC)
{
uint32_t pTxMailbox = 0;
Can_Tx.StdId = StdId;//标准ID
Can_Tx.ExtId = ExtId;//扩展ID
Can_Tx.IDE = IDE;//CAN_ID_STD为标准ID CAN_ID_EXT为使用扩展ID
Can_Tx.RTR = RTR; //0(CAN_RTR_DATA)为数据帧 1(CAN_RTR_REMOTE)为远程帧
Can_Tx.DLC = DLC; //数据长度
printf("TX ID:0x%X\r\n",ExtId);
printf("TX DATA:%02X%02X%02X%02X%02X%02X%02X%02X\r\n",Txdata[0],Txdata[1],Txdata[2],Txdata[3],Txdata[4],Txdata[5],Txdata[6],Txdata[7]);
HAL_CAN_AddTxMessage(&hcan,&Can_Tx,Txdata,&pTxMailbox);
}
void sendmessage(uint32_t StdId,uint32_t ExtId,uint8_t IDE,uint8_t RTR, uint8_t DLC,float send_data)
{
uint32_t pTxMailbox = 0;
uint8_t i;
Can_Tx.StdId = StdId;//标准ID
Can_Tx.ExtId = ExtId;//扩展ID
Can_Tx.IDE = IDE;//CAN_ID_STD为标准ID CAN_ID_EXT为使用扩展ID
Can_Tx.RTR = RTR; //0(CAN_RTR_DATA)为数据帧 1(CAN_RTR_REMOTE)为远程帧
Can_Tx.DLC = DLC; //数据长度
//将浮点数转化成4个字节存在tdata[4]----tdata[7]中
send_data=send_data*100;
Txdata[4] = (int)send_data&0x00ff;
Txdata[3] = (int)send_data>>8;
Txdata[1] = 0x01;
printf("TX ID:0x%X\r\n",Can_Tx.ExtId);
printf("TX DATA:%02X%02X%02X%02X%02X%02X%02X%02X\r\n",Txdata[0],Txdata[1],Txdata[2],Txdata[3],Txdata[4],Txdata[5],Txdata[6],Txdata[7]);
HAL_CAN_AddTxMessage(&hcan,&Can_Tx,Txdata,&pTxMailbox);
}
在can.h/* USER CODE BEGIN Prototypes */下
添加此代码
void CAN_User_Init(CAN_HandleTypeDef* hcan );
void sendmessage(uint32_t StdId,uint32_t ExtId,uint8_t IDE,uint8_t RTR, uint8_t DLC,float send_data);
void sendOrder(uint32_t StdId,uint32_t ExtId,uint8_t IDE,uint8_t RTR, uint8_t DLC);
CAN中断代码编写
stm32f1xx_it.c文件/* USER CODE BEGIN Includes *下
添加
#include "can.h"
#include "gpio.h"
#include "usart.h"
/* USER CODE BEGIN EV */下添加
extern CAN_RxHeaderTypeDef Can_Rx;
extern uint8_t Rxdata[8] ;
extern float rxdata;
uint8_t can_rx_finish_flag;//接收完成标志位
/* USER CODE BEGIN 1 */下添加
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef* hcan1)
{
uint8_t i;
printf("***********************************************\r\n");
HAL_CAN_GetRxMessage(&hcan,CAN_RX_FIFO0,&Can_Rx,Rxdata);
can_rx_finish_flag=1;
printf("RX ID:0x%X\r\n",Can_Rx.ExtId);
printf("RX DATA: %02X%02X%02X%02X%02X%02X%02X%02X\r\n",Rxdata[0],Rxdata[1],Rxdata[2],Rxdata[3],Rxdata[4],Rxdata[5],Rxdata[6],Rxdata[7]);
}
main.c中
/* USER CODE BEGIN 0 */下添加
CAN_TxHeaderTypeDef Can_Tx;
CAN_RxHeaderTypeDef Can_Rx;
uint8_t Rxdata[8];//CAN接收缓冲区
uint8_t Txdata[8] = {0};//CAN发送缓冲区
extern uint8_t can_rx_finish_flag;//接收完成标志位
/* USER CODE BEGIN 2 */下添加
CAN_User_Init(&hcan);
/* USER CODE BEGIN 3 */下添加
if(can_rx_finish_flag==1)//接收完成
{
sendmessage(0x123,0x14550151,CAN_ID_EXT,0,8,26.2);
can_rx_finish_flag=0;
}
接收端主要代码已编写完成
发送端只需把
/* USER CODE BEGIN 3 */下代码改成
Txdata[0]=0x01;
Txdata[1]=0x01;
Txdata[2]=0x04;
sendOrder(0x123,0x13550151,CAN_ID_EXT,0,3);
HAL_Delay(2000);
即可
到此STM32F103C8T6配置CAN 通信即可完成
实验现象是发送端每2秒发送一条命令 ,接收端收到后打印出接收到的数据 并返回一串数据