zoukankan      html  css  js  c++  java
  • STM32 CAN 发送接收的简单测试

    can接口相对是一种常用的串行接口,但是不像spi、i2c、uart等接口都有主从的关系,can可以任何一个节点主动发送数据,并且假如出现总线冲突会有硬件来处理。

    can和rs485又有些类似,都是把ttl信号转换成了差分信号。所以在stm32 使用can的时候会有一个can收发器。

    STM32 CAN 发送的简单测试
    从电路上看起来也很简单,stm32也是通过can tx、rx两根线和收发器相连。所以假如我们要测试can的发送,是不是只接can tx脚就可以了?

    我最开始也以为这样就可以,但是深究can的总线冲突检测原理就会发现这样行不通的。因为can 在发送数据的时候也会同时接收发送的数据,通过把接收的数据和内部发送寄存器的数据做对比,是不是一致就知道总线有没有冲突。所以在正常情况(这里意味着非正常情况下也可以)下can rx不接就到这发送出去的数据无法收到从而硬件自动判断为发送失败。

    所以要保证发送数据成功,can tx脚和can rx脚要都接上,并且确保can收发器供电正常。

    硬件上就这些主要注意点,接下来就主要是软件的配置了。

    一般stm32 配置can有以下几大步骤:

    can的初始化(cubemx直接可以生成代码)
    can的启动
    can滤波器的设置(用来接收的,发送的时候可以不用配置它)
    can执行发送数据请求
    我们只测试can的发送,所以就只用关系1、2、4步骤就可以了。

    第一步,配置stm32cubemx

    STM32 CAN 发送的简单测试
    如上图所示,最关键主要配置如下三个参数,分频数我这里配置48,下面的time Quantum值就会自动计算出来。因为can时钟是48mhz经过48分频后,一个单位时间就是1us=1000ns。

    因为我想要100k波特率,然后填写下面的Time segment1(简称 Tbs1 )和Time segment2 (简称 Tbs2) 为5和4。那么具体波特率该怎么计算还是要看看官方手册的描述:

    STM32 CAN 发送的简单测试
    根据如上描述,能决定波特率的也就是三个参数:分频值、Tbs1、Tbs2。需要注意的是,这个SYNC_SEG的1tq是固定值。和stm32cubemx中的jump width不要弄混淆了。jump width这个时间参数是作为补偿时间的上线,当时间有偏差的时候,就会自动补偿,最长时间不能超过该参数设定值。

    第二步,stm32cubemx生成的CAN代码是不带过滤器的,需要自己手动添加。

    typedef struct
    {
    	uint32_t mailbox;
    	CAN_TxHeaderTypeDef hdr;
    	uint8_t payload[8];
    }CAN_TxPacketTypeDef;
    
    typedef struct
    {
    	CAN_RxHeaderTypeDef hdr;
    	uint8_t payload[8];
    }CAN_RxPacketTypeDef;
    
    /// CAN过滤器寄存器位宽类型定义
    typedef union
    {
        __IO uint32_t value;
        struct
        {
            uint8_t REV : 1;			///< [0]    :未使用
            uint8_t RTR : 1;			///< [1]    : RTR(数据帧或远程帧标志位)
            uint8_t IDE : 1;			///< [2]    : IDE(标准帧或扩展帧标志位)
            uint32_t EXID : 18;			///< [21:3] : 存放扩展帧ID
            uint16_t STID : 11;			///< [31:22]: 存放标准帧ID
        } Sub;
    } CAN_FilterRegTypeDef;
    
    
    #define CAN_BASE_ID 0						///< CAN标准ID,最大11位,也就是0x7FF
    
    #define CAN_FILTER_MODE_MASK_ENABLE 1		///< CAN过滤器模式选择:=0:列表模式  =1:屏蔽模式
    
    #define CAN_ID_TYPE_STD_ENABLE      1       ///< CAN过滤ID类型选择:=1:标准ID,=0:扩展ID
    
    void CAN_Filter_Config(void)
    {
        CAN_FilterTypeDef sFilterConfig;
        CAN_FilterRegTypeDef IDH = {0};
        CAN_FilterRegTypeDef IDL = {0};
    
    #if CAN_ID_TYPE_STD_ENABLE
        IDH.Sub.STID = (CAN_BASE_ID >> 16) & 0xFFFF;		// 标准ID高16位
        IDL.Sub.STID = (CAN_BASE_ID & 0xFFFF);				// 标准ID低16位
    #else
        IDH.Sub.EXID = (CAN_BASE_ID >> 16) & 0xFFFF;		// 扩展ID高16位
        IDL.Sub.EXID = (CAN_BASE_ID & 0xFFFF);				// 扩展ID低16位
        IDL.Sub.IDE  = 1;									// 扩展帧标志位置位
    #endif
        sFilterConfig.FilterBank           = 0;												// 设置过滤器组编号
    #if CAN_FILTER_MODE_MASK_ENABLE
        sFilterConfig.FilterMode           = CAN_FILTERMODE_IDMASK;							// 屏蔽位模式
    #else
        sFilterConfig.FilterMode           = CAN_FILTERMODE_IDLIST;							// 列表模式
    #endif
        sFilterConfig.FilterScale          = CAN_FILTERSCALE_32BIT;							// 32位宽
        sFilterConfig.FilterIdHigh         = IDH.value;										// 标识符寄存器一ID高十六位,放入扩展帧位
        sFilterConfig.FilterIdLow          = IDL.value;										// 标识符寄存器一ID低十六位,放入扩展帧位
        sFilterConfig.FilterMaskIdHigh     = IDH.value;										// 标识符寄存器二ID高十六位,放入扩展帧位
        sFilterConfig.FilterMaskIdLow      = IDL.value;										// 标识符寄存器二ID低十六位,放入扩展帧位
        sFilterConfig.FilterFIFOAssignment = CAN_RX_FIFO0;									// 过滤器组关联到FIFO0
        sFilterConfig.FilterActivation     = ENABLE;										// 激活过滤器
        sFilterConfig.SlaveStartFilterBank = 14;											// 设置从CAN的起始过滤器编号,本单片机只有一个CAN,顾此参数无效
        if (HAL_CAN_ConfigFilter(&hcan, &sFilterConfig) != HAL_OK)
        {
            Error_Handler();
        }
    }
    
    uint8_t CAN_Transmit(CAN_TxPacketTypeDef* packet)
    {
    	if(HAL_CAN_AddTxMessage(&hcan, &packet->hdr, packet->payload, &packet->mailbox) != HAL_OK)
    		return 1;
    	return 0;
    }
    
    void CAN_Init(void)
    {
        MX_CAN_Init();
        CAN_Filter_Config();
        HAL_CAN_Start(&hcan);
        HAL_CAN_ActivateNotification(&hcan, CAN_IT_RX_FIFO0_MSG_PENDING);					// 使能CAN接收中断
    }
    
    void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *canHandle)
    {
    	static CAN_RxPacketTypeDef packet;
    	
        // CAN数据接收
        if (canHandle->Instance == hcan.Instance)
        {
            if (HAL_CAN_GetRxMessage(canHandle, CAN_RX_FIFO0, &packet.hdr, packet.payload) == HAL_OK)		// 获得接收到的数据头和数据
            {
    			printf("
    
    
    ################### CAN RECV ###################
    ");
    			printf("STID:0x%X
    ",packet.hdr.StdId);
    			printf("EXID:0x%X
    ",packet.hdr.ExtId);
    			printf("DLC :%d
    ", packet.hdr.DLC);
    			printf("DATA:");
    			for(int i = 0; i < packet.hdr.DLC; i++)
    			{
    				printf("0x%02X ", packet.payload[i]);
    			}
               HAL_CAN_ActivateNotification(canHandle, CAN_IT_RX_FIFO0_MSG_PENDING);						// 再次使能FIFO0接收中断
            }
        }
    }
    
    CAN_TxPacketTypeDef g_CanTxPacket;
    
    void CAN_SetTxPacket(void)
    {
    	g_CanTxPacket.hdr.StdId = 0x321;			// 标准ID
    //	g_CanTxPacket.hdr.ExtId = 0x10F01234;		// 扩展ID
    	g_CanTxPacket.hdr.IDE = CAN_ID_STD;			// 标准ID类型
    //	g_CanTxPacket.hdr.IDE = CAN_ID_EXT;			// 扩展ID类型
    	g_CanTxPacket.hdr.DLC = 8;					// 数据长度
    	g_CanTxPacket.hdr.RTR = CAN_RTR_DATA;		// 数据帧
    //	g_CanTxPacket.hdr.RTR = CAN_RTR_REMOTE;		// 远程帧
    	g_CanTxPacket.hdr.TransmitGlobalTime = DISABLE;
    	
    	for(int i = 0; i < 8; i++)
    	{
    		g_CanTxPacket.payload[i] = i;
    	}
    }
    
    int main()
    {
        HAL_Init();
        SystemClock_Config();
        MX_GPIO_Init();
        MX_USART1_UART_Init();
        CAN_Init();
    	printf("----------------------------------------
    ");
    
    	CAN_SetTxPacket();
    	
        while(1)
        {
    		if(CAN_Transmit(&g_CanTxPacket) != 0)
    			printf("failed
    ");
    		HAL_Delay(1000);
        }
    }
    
  • 相关阅读:
    HTML编码规范(转)
    ASP.NET连接MySQL数据库方法(测试可行)
    Redis源码解析05: 压缩列表
    Redis源码解析04: 跳跃表
    Redis源码解析03: 字典的遍历
    Redis源码解析02: 字典
    Redis源码解析01: 简单动态字符串SDS
    小象垃圾分类小程序从开始到结束
    spring boot踩坑记
    spring boot打包问题
  • 原文地址:https://www.cnblogs.com/mengydz/p/12965125.html
Copyright © 2011-2022 走看看