【沁恒CH32V307开发板测评】CAN测试
上一篇测评文章玩了一下SPI接口,还是很顺利的一、CAN介绍
1、CAN是什么
CAN(Controller Area Network)是一种基于差分信号的异步串行通信协议,由博世公司于1983年开发,专为解决复杂系统中电子设备的实时数据交换问题。
其核心设计思想为:
1)多主竞争,智能仲裁:任何节点均可主动发送数据,通过ID优先级(数值越小优先级越高)实现非破坏性仲裁,高优先级数据自动抢占总线
2)差分抗扰,高可靠传输:通过CAN_H/CAN_L双绞线传输差分信号,电压差>0.9V为显性(逻辑0),<0.5V为隐性(逻辑1)。此设计天然抑制共模干扰,适合强电磁环境(如汽车引擎舱)
3)极简布线,高扩展性:双线总线可连接多达110个节点,新增设备无需修改网络地址
通俗一点的理解,可以把CAN总线想象成个高效的会议讨论组:
发言规则:谁有紧急消息(ID优先级高)谁先说,其他人自动静音等待(非破坏性仲裁)。
抗干扰能力:成员戴降噪耳机(差分信号)确保在嘈杂环境中听清指令。
容错机制:有人报错数据时,系统自动要求重说(错误重传)
2、CAN的应用场景
主要有三大应用场景
1)汽车电子(最核心场景)
连接发动机控制、ABS刹车、仪表盘等模块。例如:踩刹车时,刹车传感器通过CAN通知发动机降速
2)工业自动化
工厂机器人、传感器群通过CAN协同工作,如机械臂收到指令后同步动作
3)智能设备
医疗监护仪、电梯控制系统、智能家居设备(如安防传感器)的内部通信
3、优势和劣势
1)优势
高可靠性、实时性强、扩展灵活、成本低
2)劣势
数据量小、速率与距离矛盾、偶发冲突问题
二、CAN代码编程
查看哪些引脚支持CAN,如图,PB8;PB9;
开发板上没有CAN收发器,因此使用的CAN收发器型号是TCAN1044;绘制的CAN收发器原理图如下:
硬件准备好了,就需要进行代码编程了
1、初始化CAN GPIO和CAN接口
void CAN_Mode_Init( u8 tsjw, u8 tbs2, u8 tbs1, u16 brp, u8 mode )
{
GPIO_InitTypeDef GPIO_InitSturcture={0};
CAN_InitTypeDef CAN_InitSturcture={0};
CAN_FilterInitTypeDef CAN_FilterInitSturcture={0};
RCC_APB2PeriphClockCmd( RCC_APB2Periph_AFIO | RCC_APB2Periph_GPIOB, ENABLE );
RCC_APB1PeriphClockCmd( RCC_APB1Periph_CAN1, ENABLE );
GPIO_PinRemapConfig( GPIO_Remap1_CAN1, ENABLE);
GPIO_InitSturcture.GPIO_Pin = GPIO_Pin_9;
GPIO_InitSturcture.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_InitSturcture.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init( GPIOB, &GPIO_InitSturcture);
GPIO_InitSturcture.GPIO_Pin = GPIO_Pin_8;
GPIO_InitSturcture.GPIO_Mode = GPIO_Mode_IPU;
GPIO_Init( GPIOB, &GPIO_InitSturcture);
CAN_InitSturcture.CAN_TTCM = DISABLE;
CAN_InitSturcture.CAN_ABOM = DISABLE;
CAN_InitSturcture.CAN_AWUM = DISABLE;
CAN_InitSturcture.CAN_NART = ENABLE;
CAN_InitSturcture.CAN_RFLM = DISABLE;
CAN_InitSturcture.CAN_TXFP = DISABLE;
CAN_InitSturcture.CAN_Mode = mode;
CAN_InitSturcture.CAN_SJW = tsjw;
CAN_InitSturcture.CAN_BS1 = tbs1;
CAN_InitSturcture.CAN_BS2 = tbs2;
CAN_InitSturcture.CAN_Prescaler = brp;
CAN_Init( CAN1, &CAN_InitSturcture );
CAN_FilterInitSturcture.CAN_FilterNumber = 0;
#if (Frame_Format == Standard_Frame)
/* identifier/mask mode, One 32-bit filter, StdId: 0x317 */
CAN_FilterInitSturcture.CAN_FilterMode = CAN_FilterMode_IdMask;
CAN_FilterInitSturcture.CAN_FilterScale = CAN_FilterScale_32bit;
CAN_FilterInitSturcture.CAN_FilterIdHigh = 0x62E0;
CAN_FilterInitSturcture.CAN_FilterIdLow = 0;
CAN_FilterInitSturcture.CAN_FilterMaskIdHigh = 0xFFE0;
CAN_FilterInitSturcture.CAN_FilterMaskIdLow = 0x0006;
2、配置过滤
/*********************************************************************
* @fn CAN_SoftFilterInit
*
* @brief Initializes the CAN peripheral according to the specified
* parameters in the CAN_FilterInitStruct.
*
* @param CAN_FilterInitStruct - pointer to a CAN_FilterInitTypeDef
* structure that contains the configuration information.
*
* @returnnone
*/
void CAN_SoftFilterInit(CAN_FilterInitTypeDef* CAN_FilterInitStruct)
{
if(CAN_FilterInitStruct->CAN_FilterNumber > CANSOFTFILTER_MAX_GROUP_NUM){
return;
}
if(CAN_FilterInitStruct->CAN_FilterActivation)
{
CANFilterStruct.en = 1;
}else
{
CANFilterStruct.en = 0;
}
CANFilterStruct.FR.FR_16_H = CAN_FilterInitStruct->CAN_FilterIdHigh;
CANFilterStruct.FR.FR_16_L = CAN_FilterInitStruct->CAN_FilterIdLow;
CANFilterStruct.FR.FR_16_H = CAN_FilterInitStruct->CAN_FilterMaskIdHigh;
CANFilterStruct.FR.FR_16_L = CAN_FilterInitStruct->CAN_FilterMaskIdLow;
CANFilterStruct.mode = CAN_FilterInitStruct->CAN_FilterMode;
CANFilterStruct.scale = CAN_FilterInitStruct->CAN_FilterScale;
}
3、配置接收中断
void USB_LP_CAN1_RX0_IRQHandler(void) __attribute__((interrupt("WCH-Interrupt-fast")));
void USB_LP_CAN1_RX0_IRQHandler()
{
int i;
uint8_t px,pbuf;
if (CAN_GetITStatus(CAN1,CAN_IT_FMP0))
{
px = CAN_Receive_Msg(pbuf);
for ( i = 0; i < px; i++)
{
canexbuf_interrupt = pbuf;
}
if(px)
{
interrupt_rx_flag = 1;
}
CAN_ClearITPendingBit(CAN1, CAN_IT_FMP0);
}
}
4、配置发送和接收函数
/*********************************************************************
* @fn CAN_Send_Msg
*
* @brief CAN Transmit function.
*
* @param msg - Transmit data buffer.
* len - Data length.
*
* @return0 - Send successful.
* 1 - Send failed.
*/
u8 CAN_Send_Msg( u8 *msg, u8 len )
{
u8 mbox;
u16 i = 0;
CanTxMsg CanTxStructure;
#if (Frame_Format == Standard_Frame)
CanTxStructure.StdId = 0x317;
CanTxStructure.IDE = CAN_Id_Standard;
#elif (Frame_Format == Extended_Frame)
CanTxStructure.ExtId = 0x12124567;
CanTxStructure.IDE = CAN_Id_Extended;
#endif
CanTxStructure.RTR = CAN_RTR_Data;
CanTxStructure.DLC = len;
for( i=0; i<len; i++ )
{
CanTxStructure.Data = msg;
}
mbox = CAN_Transmit( CAN1, &CanTxStructure);
i = 0;
while( ( CAN_TransmitStatus( CAN1, mbox ) != CAN_TxStatus_Ok ) && (i < 0xFFF) )
{
i++;
}
if( i == 0xFFF )
{
return 1;
}
else
{
return 0;
}
}
/*********************************************************************
* @fn CAN_Receive_Msg
*
* @brief CAN Receive function.
*
* @param buf - Receive data buffer.
* len - Data length.
*
* @returnCanRxStructure.DLC - Receive data length.
*/
u8 CAN_Receive_Msg( u8 *buf )
{
u8 i;
CanRxMsg CanRxStructure;
if( CAN_MessagePending( CAN1, CAN_FIFO0 ) == 0)
{
return 0;
}
#ifdef USE_SOFT_FILTER
CAN_ReceiveViaSoftFilter( CAN1, CAN_FIFO0, &CanRxStructure );
#else
CAN_Receive( CAN1, CAN_FIFO0, &CanRxStructure );
#endif // USE_SOFT_FILTER
for( i=0; i<8; i++ )
{
buf = CanRxStructure.Data;
}
return CanRxStructure.DLC;
}
5、下载验证
1)发送数据
250K波特率
1M波特率接收
统计发送成功的次数,按1M的波特率去发送,没有出错;发送58055次数据。
2)接收数据
使用USB-CAN软件向开发板发送数据,如图,设备成功接收到
总结:根据测试和数据手册说明,CH32V307VCY6的can最大速率为1M,且稳定性是很不错的,具体还需要根据现场实际情况进行测试。
页:
[1]