[AT32F403/403A] AT32F403A 替换 STM32F105 移植双can通讯

[复制链接]
323|2
AuroraWaltz 发表于 2025-9-30 13:41 | 显示全部楼层 |阅读模式
硬件
        硬件方面使用的是自己画的板子,使用的AT32F403ARCT7,外设方面有USART2、USART3、CAN1、CAN2、SPI、IIC、USB、SDIO;USART接的是max485的芯片;CAN的收发芯片都是SIT1050(芯力特国产品牌,可替换tja1050);SPI的是接了一颗W25Q128,16M的容量;IIC接的是一颗AT24C04;SDIO可插SD卡。仿真口以及串口1则使用的ATLINK的接口定义,直接使用ATLINK插上即可。USART2和USART3的485芯片,可以通过跳线帽对接起来;CAN1和CAN2也是一样。

        本测试是使用的板子上的CAN1和CAN2互发信息,所以右上角的用跳线帽把H1和H2对接,L1和L2对接。
3681968d627ba5ee31.jpg
软件


        测试使用的软件是stm32f105的3.5标准库的工程代码。由于AT32F403A的CAN2和stm32f105的CAN2是存在差异的,AT32的CAN1和CAN2是相互独立的,滤波器也是相互独立的,而f105的CAN2和CAN1有关联,所以必须修改库才能使用CAN2。

        系统时钟差异:AT32时钟配置是可以直接替换f103的,但是f103和f105的系统时钟是不一样的,所以需要配置系统时钟的和f103的一样的。
  1. void RCC_Config(void)
  2. {
  3.   u8 HSEStartUpStatus = 0;
  4.   
  5.   RCC_DeInit();                     //初始化

  6.   RCC_HSEConfig(RCC_HSE_ON);        //时能外部晶振

  7.   HSEStartUpStatus = RCC_WaitForHSEStartUp();

  8.   if(HSEStartUpStatus == SUCCESS)
  9.   {
  10.     RCC_PCLK2Config(RCC_HCLK_Div1);                         //APB2预分频    /* PCLK2 = HCLK 最大72Mhz*/

  11.     RCC_PCLK1Config(RCC_HCLK_Div2);                         //APB1预分频 = 72Mhz / 2 = 36MHz    /* PCLK1 = HCLK/4 最大36MHz*/

  12.     RCC_HCLKConfig(RCC_SYSCLK_Div1);                        //AHB预分频     /* HCLK = SYSCLK */

  13.     RCC_PLLConfig(RCC_PLLSource_PREDIV1, RCC_PLLMul_9);     /* PLLCLK = 8MHz * 9 = 72 MHz */

  14.     RCC_PLLCmd(ENABLE);                                     /* Enable PLL */

  15.     while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET)      /* Wait till PLL is ready */
  16.     {
  17.     }

  18.     RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);              /* Select PLL as system clock source */

  19.     while(RCC_GetSYSCLKSource() != 0x08)                    /* Wait till PLL is used as system clock source */
  20.     {
  21.     }   
  22.   }
  23. }
中断号差异:
4629568d627e035d55.png
CAN滤波器初始化函数:
  1. void CAN_FilterInit(CAN_TypeDef* CANx,CAN_FilterInitTypeDef* CAN_FilterInitStruct)    //AT32 CAN2
  2. {
  3.   uint32_t filter_number_bit_pos = 0;
  4.   /* Check the parameters */
  5.   assert_param(IS_CAN_ALL_PERIPH(CANx));
  6.   assert_param(IS_CAN_FILTER_NUMBER(CAN_FilterInitStruct->CAN_FilterNumber));
  7.   assert_param(IS_CAN_FILTER_MODE(CAN_FilterInitStruct->CAN_FilterMode));
  8.   assert_param(IS_CAN_FILTER_SCALE(CAN_FilterInitStruct->CAN_FilterScale));
  9.   assert_param(IS_CAN_FILTER_FIFO(CAN_FilterInitStruct->CAN_FilterFIFOAssignment));
  10.   assert_param(IS_FUNCTIONAL_STATE(CAN_FilterInitStruct->CAN_FilterActivation));

  11.   filter_number_bit_pos = ((uint32_t)1) << CAN_FilterInitStruct->CAN_FilterNumber;

  12.   /* Initialisation mode for the filter */
  13.   CANx->FMR |= FMR_FINIT;

  14.   /* Filter Deactivation */
  15.   CANx->FA1R &= ~(uint32_t)filter_number_bit_pos;

  16.   /* Filter Scale */
  17.   if (CAN_FilterInitStruct->CAN_FilterScale == CAN_FilterScale_16bit)
  18.   {
  19.     /* 16-bit scale for the filter */
  20.     CANx->FS1R &= ~(uint32_t)filter_number_bit_pos;

  21.     /* First 16-bit identifier and First 16-bit mask */
  22.     /* Or First 16-bit identifier and Second 16-bit identifier */
  23.     CANx->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR1 =
  24.     ((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdLow) << 16) |
  25.         (0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdLow);

  26.     /* Second 16-bit identifier and Second 16-bit mask */
  27.     /* Or Third 16-bit identifier and Fourth 16-bit identifier */
  28.     CANx->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR2 =
  29.     ((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdHigh) << 16) |
  30.         (0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdHigh);
  31.   }

  32.   if (CAN_FilterInitStruct->CAN_FilterScale == CAN_FilterScale_32bit)
  33.   {
  34.     /* 32-bit scale for the filter */
  35.     CANx->FS1R |= filter_number_bit_pos;
  36.     /* 32-bit identifier or First 32-bit identifier */
  37.     CANx->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR1 =
  38.     ((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdHigh) << 16) |
  39.         (0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterIdLow);
  40.     /* 32-bit mask or Second 32-bit identifier */
  41.     CANx->sFilterRegister[CAN_FilterInitStruct->CAN_FilterNumber].FR2 =
  42.     ((0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdHigh) << 16) |
  43.         (0x0000FFFF & (uint32_t)CAN_FilterInitStruct->CAN_FilterMaskIdLow);
  44.   }

  45.   /* Filter Mode */
  46.   if (CAN_FilterInitStruct->CAN_FilterMode == CAN_FilterMode_IdMask)
  47.   {
  48.     /*Id/Mask mode for the filter*/
  49.     CANx->FM1R &= ~(uint32_t)filter_number_bit_pos;
  50.   }
  51.   else /* CAN_FilterInitStruct->CAN_FilterMode == CAN_FilterMode_IdList */
  52.   {
  53.     /*Identifier list mode for the filter*/
  54.     CANx->FM1R |= (uint32_t)filter_number_bit_pos;
  55.   }

  56.   /* Filter FIFO assignment */
  57.   if (CAN_FilterInitStruct->CAN_FilterFIFOAssignment == CAN_Filter_FIFO0)
  58.   {
  59.     /* FIFO 0 assignation for the filter */
  60.     CANx->FFA1R &= ~(uint32_t)filter_number_bit_pos;
  61.   }

  62.   if (CAN_FilterInitStruct->CAN_FilterFIFOAssignment == CAN_Filter_FIFO1)
  63.   {
  64.     /* FIFO 1 assignation for the filter */
  65.     CANx->FFA1R |= (uint32_t)filter_number_bit_pos;
  66.   }
  67.   
  68.   /* Filter activation */
  69.   if (CAN_FilterInitStruct->CAN_FilterActivation == ENABLE)
  70.   {
  71.     CANx->FA1R |= filter_number_bit_pos;
  72.   }

  73.   /* Leave the initialisation mode for the filter */
  74.   CANx->FMR &= ~FMR_FINIT;
  75. }
软件相关部分:


    由于CAN1的IO是使用的PB8,PB9,使用的是重映射1,软件需要配置重映射。


软件方面设定CAN的波特率是500k,使用的中断方式接收数据,接收到的帧的ID如果是我们设定的ID那就把收到的数据给打印出来,CAN1发送的帧的ID是0x11,CAN2发送的帧的ID是0x12。


相关代码如下:
  1. u8 CAN1_Init(void)
  2. {
  3.         GPIO_InitTypeDef                 GPIO_InitStructure;
  4.         CAN_InitTypeDef                CAN_InitStructure;
  5.         CAN_FilterInitTypeDef          CAN_FilterInitStructure;
  6.         NVIC_InitTypeDef                  NVIC_InitStructure;


  7.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);                //使能GPIOB时钟         
  8.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE);       

  9.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);                //使能CAN1时钟

  10.         GPIO_PinRemapConfig(GPIO_Remap1_CAN1,ENABLE);

  11.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  12.         GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  13.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;                                //复用推挽
  14.         GPIO_Init(GPIOB, &GPIO_InitStructure);                                                //初始化IO

  15.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  16.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;                                //上拉输入
  17.         GPIO_Init(GPIOB, &GPIO_InitStructure);                                                //初始化IO

  18.         //CAN单元设置
  19.         CAN_InitStructure.CAN_TTCM=DISABLE;                        //非时间触发通信模式  
  20.         CAN_InitStructure.CAN_ABOM=ENABLE;                        //软件自动离线管理         
  21.         CAN_InitStructure.CAN_AWUM=ENABLE;                        //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
  22.         CAN_InitStructure.CAN_NART=DISABLE;                        //禁止报文自动传送
  23.         CAN_InitStructure.CAN_RFLM=DISABLE;                         //报文不锁定,新的覆盖旧的  
  24.         CAN_InitStructure.CAN_TXFP=DISABLE;                        //优先级由报文标识符决定
  25.         CAN_InitStructure.CAN_Mode= CAN_Mode_Normal;                //模式设置: mode:0,普通模式;1,回环模式;
  26.        
  27.         //设置波特率  36M/((8+9+1)*4)=500Kbps
  28.         CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;                                //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位  CAN_SJW_1tq         CAN_SJW_2tq CAN_SJW_3tq CAN_SJW_4tq
  29.         CAN_InitStructure.CAN_BS1=CAN_BS1_9tq;                         //Tbs1=tbs1+1个时间单位CAN_BS1_1tq ~CAN_BS1_16tq
  30.         CAN_InitStructure.CAN_BS2=CAN_BS2_8tq;                                //Tbs2=tbs2+1个时间单位CAN_BS2_1tq ~        CAN_BS2_8tq
  31.         CAN_InitStructure.CAN_Prescaler=4;        //分频系数(Fdiv)为brp+1       
  32.         CAN_Init(CAN1, &CAN_InitStructure);                //初始化CAN1

  33.         CAN_FilterInitStructure.CAN_FilterNumber=0;        //过滤器0
  34.         CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;         //屏蔽位模式
  35.         CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;         //32位宽
  36.         CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;        //32位ID
  37.         CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
  38.         CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASK
  39.         CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
  40.         CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
  41.         CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;//激活过滤器0

  42.         CAN_FilterInit(CAN1,&CAN_FilterInitStructure);                        //滤波器初始化
  43.        

  44.         CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE);                                //FIFO0消息挂号中断允许.                    

  45.         NVIC_InitStructure.NVIC_IRQChannel = CAN1_RX0_IRQn;
  46.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;     // 主优先级为1
  47.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;            // 次优先级为0
  48.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  49.         NVIC_Init(&NVIC_InitStructure);

  50.         return 0;
  51. }


  52. u8 CAN2_Init()
  53. {
  54.         GPIO_InitTypeDef                 GPIO_InitStructure;
  55.         CAN_InitTypeDef                CAN_InitStructure;
  56.         CAN_FilterInitTypeDef          CAN_FilterInitStructure;
  57.         NVIC_InitTypeDef                  NVIC_InitStructure;


  58.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能GPIOB时钟                                                                                                                    

  59.         RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN2, ENABLE);//使能CAN2时钟       

  60.     //CAN2 GPIO配置
  61.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;
  62.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;           //带上拉输入
  63.     GPIO_Init(GPIOB, &GPIO_InitStructure);       
  64.     GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
  65.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  66.     GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;         //推挽输出
  67.     GPIO_Init(GPIOB, &GPIO_InitStructure);

  68.         //CAN单元设置
  69.         CAN_InitStructure.CAN_TTCM=DISABLE;                        //非时间触发通信模式  
  70.         CAN_InitStructure.CAN_ABOM=ENABLE;                        //软件自动离线管理         
  71.         CAN_InitStructure.CAN_AWUM=ENABLE;                        //睡眠模式通过软件唤醒(清除CAN->MCR的SLEEP位)
  72.         CAN_InitStructure.CAN_NART=DISABLE;                        //禁止报文自动传送
  73.         CAN_InitStructure.CAN_RFLM=DISABLE;                         //报文不锁定,新的覆盖旧的  
  74.         CAN_InitStructure.CAN_TXFP=DISABLE;                        //优先级由报文标识符决定
  75.         CAN_InitStructure.CAN_Mode= CAN_Mode_Normal;                //模式设置: mode:0,普通模式;1,回环模式;

  76.         //设置波特率  36M/((8+9+1)*4)=500Kbps
  77.         CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;                                //重新同步跳跃宽度(Tsjw)为tsjw+1个时间单位  CAN_SJW_1tq         CAN_SJW_2tq CAN_SJW_3tq CAN_SJW_4tq
  78.         CAN_InitStructure.CAN_BS1=CAN_BS1_9tq;                         //Tbs1=tbs1+1个时间单位CAN_BS1_1tq ~CAN_BS1_16tq
  79.         CAN_InitStructure.CAN_BS2=CAN_BS2_8tq;                                //Tbs2=tbs2+1个时间单位CAN_BS2_1tq ~        CAN_BS2_8tq
  80.         CAN_InitStructure.CAN_Prescaler=4;        //分频系数(Fdiv)为brp+1       
  81.         CAN_Init(CAN2, &CAN_InitStructure);                //初始化CAN1

  82.         CAN_FilterInitStructure.CAN_FilterNumber=0;        //过滤器0
  83.         CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;         //屏蔽位模式
  84.         CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit;         //32位宽
  85.         CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000;        //32位ID
  86.         CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
  87.         CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000;//32位MASK
  88.         CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
  89.         CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;//过滤器0关联到FIFO0
  90.         CAN_FilterInitStructure.CAN_FilterActivation=ENABLE;//激活过滤器0

  91.         CAN_FilterInit(CAN2,&CAN_FilterInitStructure);                        //滤波器初始化
  92.        

  93.         CAN_ITConfig(CAN2,CAN_IT_FMP0,ENABLE);                                //FIFO0消息挂号中断允许.                    

  94.         NVIC_InitStructure.NVIC_IRQChannel = CAN2_RX0_IRQn;
  95.         NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;     // 主优先级为1
  96.         NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;            // 次优先级为0
  97.         NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  98.         NVIC_Init(&NVIC_InitStructure);

  99.         return 0;
  100. }


  101. //中断服务函数                            
  102. void CAN1_RX0_IRQHandler(void)
  103. {
  104.           CanRxMsg RxMessage;
  105.         int i=0;
  106.     CAN_Receive(CAN1, 0, &RxMessage);
  107.         printf ("CAN1_RX0_IRQHandler:\r\n");
  108.         if(RxMessage.StdId==0x12)
  109.         {
  110.                 printf ("rxbuf:\r\n");
  111.                 for(i=0;i<8;i++)
  112.                 printf("%02x ",RxMessage.Data[i]);
  113.         }
  114.         printf("\r\n");
  115. }

  116. void CAN2_RX0_IRQHandler(void)
  117. {
  118.           CanRxMsg RxMessage;
  119.         int i=0;
  120.     CAN_Receive(CAN2, 0, &RxMessage);
  121.         printf ("CAN2_RX0_IRQHandler:\r\n");
  122.         if(RxMessage.StdId==0x11)
  123.         {
  124.                 printf ("rxbuf:\r\n");
  125.                 for(i=0;i<8;i++)
  126.                 printf("%02x ",RxMessage.Data[i]);
  127.         }
  128.         printf("\r\n");
  129. }




  130. //can发送一组数据(固定格式:ID为0X12,标准帧,数据帧)       
  131. //len:数据长度(最大为8)                                     
  132. //msg:数据指针,最大为8个字节.
  133. //返回值:0,成功;
  134. //                 其他,失败;
  135. u8 Can1_Send_Msg()
  136. {       
  137.         u8 mbox;
  138.         u16 i=0;
  139.         CanTxMsg TxMessage;
  140.         TxMessage.StdId=0x11;                        // 标准标识符
  141.         TxMessage.ExtId=0x12;                        // 设置扩展标示符
  142.         TxMessage.IDE=CAN_Id_Standard;         // 标准帧
  143.         TxMessage.RTR=CAN_RTR_Data;                // 数据帧
  144.         TxMessage.DLC=8;                                // 要发送的数据长度

  145.         TxMessage.Data[0]=0x01;
  146.         TxMessage.Data[1]=0x01;
  147.         TxMessage.Data[2]=0x01;
  148.         TxMessage.Data[3]=0x01;
  149.         TxMessage.Data[4]=0x01;
  150.         TxMessage.Data[5]=0x01;
  151.         TxMessage.Data[6]=0x01;
  152.         TxMessage.Data[7]=0x01;       
  153.        
  154.         mbox= CAN_Transmit(CAN1, &TxMessage);   
  155.         i=0;
  156.         while((CAN_TransmitStatus(CAN1, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++;        //等待发送结束
  157.         if(i>=0XFFF)return 1;
  158.         return 0;         
  159. }

  160. u8 Can2_Send_Msg()
  161. {       
  162.         u8 mbox;
  163.         u16 i=0;
  164.         CanTxMsg TxMessage;
  165.         TxMessage.StdId=0x12;                        // 标准标识符
  166.         TxMessage.ExtId=0x12;                        // 设置扩展标示符
  167.         TxMessage.IDE=CAN_Id_Standard;         // 标准帧
  168.         TxMessage.RTR=CAN_RTR_Data;                // 数据帧
  169.         TxMessage.DLC=8;                                // 要发送的数据长度

  170.         TxMessage.Data[0]=0x02;
  171.         TxMessage.Data[1]=0x02;
  172.         TxMessage.Data[2]=0x02;
  173.         TxMessage.Data[3]=0x02;
  174.         TxMessage.Data[4]=0x02;
  175.         TxMessage.Data[5]=0x02;
  176.         TxMessage.Data[6]=0x02;
  177.         TxMessage.Data[7]=0x02;       
  178.        
  179.         mbox= CAN_Transmit(CAN2, &TxMessage);   
  180.         i=0;
  181.         while((CAN_TransmitStatus(CAN2, mbox)==CAN_TxStatus_Failed)&&(i<0XFFF))i++;        //等待发送结束
  182.         if(i>=0XFFF)return 1;
  183.         return 0;         
  184. }


  185. int main(void)
  186. {         

  187.     u8 t=0;
  188.         RCC_Config();
  189.         delay_init();                     //延时函数初始化          
  190.         NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//设置中断优先级分组为组2:2位抢占优先级,2位响应优先级
  191.         uart_init(115200);                 //串口初始化为115200
  192.         printf ("AT32F403A 替换SXX32f105 双can通讯测试!!\r\n");
  193.         AT32LED_Init();                                          

  194.         CAN1_Init();
  195.         CAN2_Init();

  196.         GetClk();
  197.        
  198.         while(1)
  199.         {                 

  200.                 t++;
  201.                 delay_ms(10);
  202.                 if(t%50==0)
  203.                 {
  204.                         LED4=!LED4;//提示系统正在运行       

  205.                 }
  206.                 if(t%100==0)
  207.                 {          
  208.                         Can1_Send_Msg();
  209.                         delay_ms(500);
  210.                         Can2_Send_Msg();
  211.                         LED2=!LED2;
  212.                 }                
  213.         }
  214. }
测试结果

       通过看串口助手的log,程序已经运行起来,收发的数据和我们设定的是一致的:

5139868d6281c0ff52.png
总结

        AT32F403A的CAN2和STM32F105的CAN2是不一样的,不能兼容。必须修改库才能在AT32上使用,主要就是中断号以及滤波器不一样。



一点点晚风 发表于 2025-9-30 15:42 | 显示全部楼层
小小总结


相同点:​​
均集成2个CAN控制器(bxCAN),软件兼容。
​​不同点:​​
​​性能​​:AT32主频更高,处理更快。
​​时钟​​:时钟树配置有差异,需修改初始化。
​​库函数​​:需将ST标准库更换为AT32的SDK。

转瞬回声 发表于 2025-9-30 17:22 | 显示全部楼层
巧了!CAN通讯芯片我也选用的是芯力特的
您需要登录后才可以回帖 登录 | 注册

本版积分规则

7

主题

74

帖子

0

粉丝
快速回复 在线客服 返回列表 返回顶部