时钟配置
时钟配置没什么特别的 外部晶振频率为25MHz
引脚配置
PE0连接到TJA1050的8脚上,使用时固定输出低电平即可。
MX CAN配置
修改了时序参数和使能了自动总线管理,其他的都为默认设置
代码
配置完成后,生成代码。生成的代码没有进行过滤器配置,需要自己添加过滤器配置代码。
在MX_CAN1_Init()中添加过滤器配置代码
为了方便测试,只使用FIFO0,过滤器使用掩码模式,配置为允许所有消息通过(相当于不过滤)
void MX_CAN1_Init(void)
{
/* USER CODE BEGIN CAN1_Init 0 */
CAN_FilterTypeDef Filter;
/* USER CODE END CAN1_Init 0 */
/* USER CODE BEGIN CAN1_Init 1 */
/* USER CODE END CAN1_Init 1 */
hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 30;
hcan1.Init.Mode = CAN_MODE_NORMAL;
hcan1.Init.SyncJumpWidth = CAN_SJW_2TQ;
hcan1.Init.TimeSeg1 = CAN_BS1_8TQ;
hcan1.Init.TimeSeg2 = CAN_BS2_5TQ;
hcan1.Init.TimeTriggeredMode = DISABLE;
hcan1.Init.AutoBusOff = ENABLE;
hcan1.Init.AutoWakeUp = DISABLE;
hcan1.Init.AutoRetransmission = DISABLE;
hcan1.Init.ReceiveFifoLocked = DISABLE;
hcan1.Init.TransmitFifoPriority = DISABLE;
if (HAL_CAN_Init(&hcan1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN CAN1_Init 2 */
//过滤器0
Filter.FilterIdHigh=0;//由于掩码全0 此段没什么用 随便给一个数
Filter.FilterIdLow=0;//由于掩码全0 此段没什么用 随便给一个数
Filter.FilterMaskIdHigh=0;//全0 不对比任何位
Filter.FilterMaskIdLow=0;//全0 不对比任何位
Filter.SlaveStartFilterBank=14;//此段配置CAN1与CAN2使用的过滤器 0~13为CAN1使用 14~...为CAN2使用
Filter.FilterScale=CAN_FILTERSCALE_32BIT;//32Bit
Filter.FilterMode=CAN_FILTERMODE_IDMASK;//掩码模式
Filter.FilterBank=0;//过滤器0
Filter.FilterFIFOAssignment=CAN_FilterFIFO0;//使用FIFO0
Filter.FilterActivation=CAN_FILTER_ENABLE;//使能过滤器
HAL_CAN_ConfigFilter(&hcan1,&Filter);//将Filter的配置设置到hcan1
HAL_CAN_Start(&hcan1);//启动hcan1
/* USER CODE END CAN1_Init 2 */
}
在main.c中添加发送接收代码
为了方便测试,我没有打开CAN的中断,使用在死循环里进行轮询的方式,每秒发送一个数据包,接收到数据包后把接收到的数据更新到CAN_RIxR,CAN_RDTxR和CAN_Data中
/* USER CODE BEGIN 0 */
//接收到的数据储存到下面的变量中
volatile unsigned int CAN_RIxR;
volatile unsigned int CAN_RDTxR;
volatile unsigned int CAN_Data[2];
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
unsigned int lastT;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_CAN1_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
lastT=(int)HAL_GetTick();//更新lastT
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//间隔1000ms调用if里面的代码一次,即使溢出也不会影响结果。除非等待时间超过0x7FFFFFFF(谁会要求间隔那么久)
if((HAL_GetTick()-lastT)>999){
lastT+=1000;
//每1000ms执行到这里一次
if((hcan1.Instance->sTxMailBox[0].TIR&CAN_TI0R_TXRQ)==0){//邮箱0是否空
hcan1.Instance->sTxMailBox[0].TDLR=0x20000607;//低4字节数据(低位先发送) 低4字节先发送
hcan1.Instance->sTxMailBox[0].TDHR=0x9DEFA478;//高4字节数据(低位先发送)
hcan1.Instance->sTxMailBox[0].TDTR=8;//发送8字节
hcan1.Instance->sTxMailBox[0].TIR=0x40000000;//ID IDE RTR 等 详见数据手册,使用两个板子相互通信时 建议ID/EXID设置为不同值
hcan1.Instance->sTxMailBox[0].TIR|=CAN_TI0R_TXRQ;//触发发送请求
}
}
//检测FIFO0是否有数据
if((hcan1.Instance->RF0R&CAN_RF0R_FMP0)!=0){
//读取接收的数据 数据布局与发送邮箱类似
CAN_RIxR=hcan1.Instance->sFIFOMailBox[0].RIR;
CAN_RDTxR=hcan1.Instance->sFIFOMailBox[0].RDTR;
CAN_Data[0]=hcan1.Instance->sFIFOMailBox[0].RDLR;
CAN_Data[1]=hcan1.Instance->sFIFOMailBox[0].RDHR;
hcan1.Instance->RF0R|=CAN_RF0R_RFOM0;
}
}
/* USER CODE END 3 */
}
测试
测试很方便,两个一样的板子,下一样的程序(仅hcan1.Instance->sTxMailBox[0].TIR的ID不同),将两个板子的CANH,CANL,连在一起。使用stlink(其他调试器也行)对其中一个板子测试,在读取接收数据那部分代码上打一个断点,即可知道有没有正常接收到数据,并且可查看接收到的数据是否正确。
调试问题
调试时发现通信并没有成功,查看CAN1->ESR寄存器,发现其中的TEC段一直在增加,错误代码LEC为0x3。然后调试另一个板子,TEC段也是一直在增加,但不同的是LEC为0x5,查手册得知这是位显性错误,然后检查板子发现单片机上的
CAN1_TX(PB9)虚焊了,补焊后程序运行就正常了。
时钟配置
时钟配置没什么特别的 外部晶振频率为25MHz
引脚配置
PE0连接到TJA1050的8脚上,使用时固定输出低电平即可。
MX CAN配置
修改了时序参数和使能了自动总线管理,其他的都为默认设置
代码
配置完成后,生成代码。生成的代码没有进行过滤器配置,需要自己添加过滤器配置代码。
在MX_CAN1_Init()中添加过滤器配置代码
为了方便测试,只使用FIFO0,过滤器使用掩码模式,配置为允许所有消息通过(相当于不过滤)
void MX_CAN1_Init(void)
{
/* USER CODE BEGIN CAN1_Init 0 */
CAN_FilterTypeDef Filter;
/* USER CODE END CAN1_Init 0 */
/* USER CODE BEGIN CAN1_Init 1 */
/* USER CODE END CAN1_Init 1 */
hcan1.Instance = CAN1;
hcan1.Init.Prescaler = 30;
hcan1.Init.Mode = CAN_MODE_NORMAL;
hcan1.Init.SyncJumpWidth = CAN_SJW_2TQ;
hcan1.Init.TimeSeg1 = CAN_BS1_8TQ;
hcan1.Init.TimeSeg2 = CAN_BS2_5TQ;
hcan1.Init.TimeTriggeredMode = DISABLE;
hcan1.Init.AutoBusOff = ENABLE;
hcan1.Init.AutoWakeUp = DISABLE;
hcan1.Init.AutoRetransmission = DISABLE;
hcan1.Init.ReceiveFifoLocked = DISABLE;
hcan1.Init.TransmitFifoPriority = DISABLE;
if (HAL_CAN_Init(&hcan1) != HAL_OK)
{
Error_Handler();
}
/* USER CODE BEGIN CAN1_Init 2 */
//过滤器0
Filter.FilterIdHigh=0;//由于掩码全0 此段没什么用 随便给一个数
Filter.FilterIdLow=0;//由于掩码全0 此段没什么用 随便给一个数
Filter.FilterMaskIdHigh=0;//全0 不对比任何位
Filter.FilterMaskIdLow=0;//全0 不对比任何位
Filter.SlaveStartFilterBank=14;//此段配置CAN1与CAN2使用的过滤器 0~13为CAN1使用 14~...为CAN2使用
Filter.FilterScale=CAN_FILTERSCALE_32BIT;//32Bit
Filter.FilterMode=CAN_FILTERMODE_IDMASK;//掩码模式
Filter.FilterBank=0;//过滤器0
Filter.FilterFIFOAssignment=CAN_FilterFIFO0;//使用FIFO0
Filter.FilterActivation=CAN_FILTER_ENABLE;//使能过滤器
HAL_CAN_ConfigFilter(&hcan1,&Filter);//将Filter的配置设置到hcan1
HAL_CAN_Start(&hcan1);//启动hcan1
/* USER CODE END CAN1_Init 2 */
}
在main.c中添加发送接收代码
为了方便测试,我没有打开CAN的中断,使用在死循环里进行轮询的方式,每秒发送一个数据包,接收到数据包后把接收到的数据更新到CAN_RIxR,CAN_RDTxR和CAN_Data中
/* USER CODE BEGIN 0 */
//接收到的数据储存到下面的变量中
volatile unsigned int CAN_RIxR;
volatile unsigned int CAN_RDTxR;
volatile unsigned int CAN_Data[2];
/* USER CODE END 0 */
/**
* @brief The application entry point.
* @retval int
*/
int main(void)
{
/* USER CODE BEGIN 1 */
unsigned int lastT;
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_CAN1_Init();
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
lastT=(int)HAL_GetTick();//更新lastT
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
//间隔1000ms调用if里面的代码一次,即使溢出也不会影响结果。除非等待时间超过0x7FFFFFFF(谁会要求间隔那么久)
if((HAL_GetTick()-lastT)>999){
lastT+=1000;
//每1000ms执行到这里一次
if((hcan1.Instance->sTxMailBox[0].TIR&CAN_TI0R_TXRQ)==0){//邮箱0是否空
hcan1.Instance->sTxMailBox[0].TDLR=0x20000607;//低4字节数据(低位先发送) 低4字节先发送
hcan1.Instance->sTxMailBox[0].TDHR=0x9DEFA478;//高4字节数据(低位先发送)
hcan1.Instance->sTxMailBox[0].TDTR=8;//发送8字节
hcan1.Instance->sTxMailBox[0].TIR=0x40000000;//ID IDE RTR 等 详见数据手册,使用两个板子相互通信时 建议ID/EXID设置为不同值
hcan1.Instance->sTxMailBox[0].TIR|=CAN_TI0R_TXRQ;//触发发送请求
}
}
//检测FIFO0是否有数据
if((hcan1.Instance->RF0R&CAN_RF0R_FMP0)!=0){
//读取接收的数据 数据布局与发送邮箱类似
CAN_RIxR=hcan1.Instance->sFIFOMailBox[0].RIR;
CAN_RDTxR=hcan1.Instance->sFIFOMailBox[0].RDTR;
CAN_Data[0]=hcan1.Instance->sFIFOMailBox[0].RDLR;
CAN_Data[1]=hcan1.Instance->sFIFOMailBox[0].RDHR;
hcan1.Instance->RF0R|=CAN_RF0R_RFOM0;
}
}
/* USER CODE END 3 */
}
测试
测试很方便,两个一样的板子,下一样的程序(仅hcan1.Instance->sTxMailBox[0].TIR的ID不同),将两个板子的CANH,CANL,连在一起。使用stlink(其他调试器也行)对其中一个板子测试,在读取接收数据那部分代码上打一个断点,即可知道有没有正常接收到数据,并且可查看接收到的数据是否正确。
调试问题
调试时发现通信并没有成功,查看CAN1->ESR寄存器,发现其中的TEC段一直在增加,错误代码LEC为0x3。然后调试另一个板子,TEC段也是一直在增加,但不同的是LEC为0x5,查手册得知这是位显性错误,然后检查板子发现单片机上的
CAN1_TX(PB9)虚焊了,补焊后程序运行就正常了。
举报