[程序源码] Canfestival运行前的准备工作

[复制链接]
1869|13
 楼主| 一路向北lm 发表于 2020-8-31 20:02 | 显示全部楼层 |阅读模式
添加串口驱动,打印CANopen输出信息


 楼主| 一路向北lm 发表于 2020-8-31 20:02 | 显示全部楼层
drives分组下添加uart驱动,使用STM32的串口1来实现打印数据,代码如下:
  1. #include "bsp_uart.h"

  2. void Uart_Config(void)
  3. {
  4.    GPIO_InitTypeDef        GPIO_InitStructure;
  5.         USART_InitTypeDef       USART_InitStructure;
  6.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能 PORTB 时钟
  7.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //使能USART1时钟
  8.        
  9.        
  10.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  11.     GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  12.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽
  13.         GPIO_Init(GPIOA, &GPIO_InitStructure);
  14.        
  15.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
  16.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING; //浮空输入
  17.         GPIO_Init(GPIOA, &GPIO_InitStructure);

  18.         USART_InitStructure.USART_BaudRate = 115200;   
  19.         USART_InitStructure.USART_WordLength = USART_WordLength_8b;        
  20.         USART_InitStructure.USART_StopBits = USART_StopBits_1;
  21.         USART_InitStructure.USART_Parity = USART_Parity_No ;
  22.         USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;
  23.         USART_InitStructure.USART_Mode = USART_Mode_Tx;
  24.         USART_Init(USART1, &USART_InitStructure);       
  25.         USART_Cmd(USART1, ENABLE);               
  26. }


 楼主| 一路向北lm 发表于 2020-8-31 20:03 | 显示全部楼层
  1. //重定向c库函数printf到串口,重定向后可使用printf函数
  2. int fputc(int ch, FILE *f)
  3. {
  4.                 /* 发送一个字节数据到串口 */
  5.                 USART_SendData(USART1, (uint8_t) ch);               
  6.                 /* 等待发送完毕 */
  7.                 while (USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);                       
  8.                 return (ch);
  9. }


 楼主| 一路向北lm 发表于 2020-8-31 20:03 | 显示全部楼层
暂不需要开启接收功能,使用main.c测试代码如下,经测试一切正常,可进行下一步。
  1. int main(void)
  2. {       
  3. Uart_Config();
  4. printf("hello canopen!\r\n");
  5.   while(1)
  6.         {
  7.         }
  8. }


 楼主| 一路向北lm 发表于 2020-8-31 20:04 | 显示全部楼层
串口助手已经输出字符串信息。

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| 一路向北lm 发表于 2020-8-31 20:04 | 显示全部楼层
添加CAN驱动,实现CAN数据的收发
现在我们已经把串口的打印功能给调试完毕了,可以正常打印数据来进行简单的调试了,下面接着完成CAN驱动部分,CAN初始化、CAN发送数据和CAN接收数据代码
 楼主| 一路向北lm 发表于 2020-8-31 20:05 | 显示全部楼层
CAN初始化部分,波特率和模式可以根据参数设定
  1. #include "bsp_can.h"

  2. /************************************************************
  3. * CAN波特率计算公式:
  4. * Baud =  32000000/BRP/(tSJW+tBS1+tBS2)
  5. *
  6. *
  7. * 1M kbps   
  8. *         tSJW = CAN_SJW_1tq     
  9. *         tBS1 = CAN_BS1_3tq     
  10. *         tBS2 = CAN_BS2_2tq     
  11. *         BRP  = 6   
  12. * 800 kbps   
  13. *         tSJW = CAN_SJW_1tq     
  14. *         tBS1 = CAN_BS1_5tq     
  15. *         tBS2 = CAN_BS2_3tq     
  16. *         BRP  = 5   
  17. * 500 kbps   
  18. *         tSJW = CAN_SJW_1tq     
  19. *         tBS1 = CAN_BS1_8tq     
  20. *         tBS2 = CAN_BS2_9tq     
  21. *         BRP  = 4   
  22. * 250 kbps   
  23. *         tSJW = CAN_SJW_1tq     
  24. *         tBS1 = CAN_BS1_3tq     
  25. *         tBS2 = CAN_BS2_2tq     
  26. *         BRP  = 24   
  27. * 200 kbps   
  28. *         tSJW = CAN_SJW_1tq     
  29. *         tBS1 = CAN_BS1_3tq     
  30. *         tBS2 = CAN_BS2_2tq     
  31. *         BRP  =  30  
  32. *************************************************************/

  33. void CAN_Config(unsigned char mode,unsigned char tSJW,unsigned char tBS1,unsigned char tBS2,unsigned char BRP)
  34. {
  35.   GPIO_InitTypeDef        GPIO_InitStructure;
  36.         CAN_InitTypeDef         CAN_InitStructure;
  37.         CAN_FilterInitTypeDef   CAN_FilterInitStructure;
  38.         NVIC_InitTypeDef        NVIC_InitStructure;

  39.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE);//使能 PORTB 时钟
  40.         RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //使能AFIO时钟
  41.   RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE); //使能 CAN1 时钟
  42.        
  43.         GPIO_PinRemapConfig(GPIO_Remap1_CAN1,ENABLE);  //CAN1部分映射到PB8和PB9
  44.        
  45.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
  46.   GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
  47.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽
  48.         GPIO_Init(GPIOB, &GPIO_InitStructure);
  49.        
  50.         GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8;
  51.         GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //上拉输入
  52.         GPIO_Init(GPIOB, &GPIO_InitStructure);
  53.        
  54.         //CAN 单元设置
  55.   CAN_InitStructure.CAN_TTCM=DISABLE; //非时间触发通信模式
  56.   CAN_InitStructure.CAN_ABOM=DISABLE; //软件自动离线管理
  57.         CAN_InitStructure.CAN_AWUM=DISABLE; //睡眠模式通过软件唤醒
  58.         CAN_InitStructure.CAN_NART=ENABLE; //禁止报文自动传送
  59.         CAN_InitStructure.CAN_RFLM=DISABLE; //报文不锁定,新的覆盖旧的
  60.         CAN_InitStructure.CAN_TXFP=DISABLE; //优先级由报文标识符决定
  61.         CAN_InitStructure.CAN_Mode= CAN_Mode_LoopBack;    //模式设置: 0,普通模式;1,回环模式;
  62.        
  63. //设置波特率
  64.   CAN_InitStructure.CAN_SJW=CAN_SJW_1tq;      //重新同步跳跃宽度(Tsjw)
  65.   CAN_InitStructure.CAN_BS1=CAN_BS1_3tq;      //时间段 1 占用时间单位
  66.   CAN_InitStructure.CAN_BS2=CAN_BS2_2tq ;      // 时间段 2 占用时间单位
  67.         CAN_InitStructure.CAN_Prescaler=6; //分频系数(Fdiv)为 brp+1
  68.   CAN_Init(CAN1, &CAN_InitStructure);  // 初始化 CAN1

  69.   //CAN过滤器设置
  70.   CAN_FilterInitStructure.CAN_FilterNumber=0; //过滤器 0
  71.         CAN_FilterInitStructure.CAN_FilterMode=CAN_FilterMode_IdMask;
  72.         CAN_FilterInitStructure.CAN_FilterScale=CAN_FilterScale_32bit; //32 位
  73.         CAN_FilterInitStructure.CAN_FilterIdHigh=0x0000; //32 位 ID
  74.         CAN_FilterInitStructure.CAN_FilterIdLow=0x0000;
  75.         CAN_FilterInitStructure.CAN_FilterMaskIdHigh=0x0000; //32 位 MASK
  76.         CAN_FilterInitStructure.CAN_FilterMaskIdLow=0x0000;
  77.         CAN_FilterInitStructure.CAN_FilterFIFOAssignment=CAN_Filter_FIFO0;// FIFO0
  78.         CAN_FilterInitStructure.CAN_FilterActivation=ENABLE; //激活过滤器 0
  79.         CAN_FilterInit(&CAN_FilterInitStructure); //滤波器初始
  80.        
  81.   CAN_ITConfig(CAN1,CAN_IT_FMP0,ENABLE); //FIFO0 消息挂号中断允许.
  82. NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;
  83.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; // 主优先级为 1
  84.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0; // 次优先级为 0
  85.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
  86.   NVIC_Init(&NVIC_InitStructure);
  87. }


 楼主| 一路向北lm 发表于 2020-8-31 20:05 | 显示全部楼层
CAN发送数据函数,一次最多发送8个字节数据
  1. /**********************************************************************
  2. *CAN发送数据函数(固定格式:ID 为 0X12,标准帧,数据帧)
  3. *len:数据长度(最大为 8)
  4. *msg:数据指针,最大为 8 个字节.
  5. *返回值:0,成功;
  6. * 其他,失败;
  7. **********************************************************************/
  8. unsigned char Can_Send_Msg(unsigned char* msg,unsigned char len)
  9. {
  10.   unsigned char mbox;
  11. unsigned int i = 0;
  12.   CanTxMsg  TxMessage;
  13.   TxMessage.StdId = 0x12; // 标准标识符为 0x12
  14.   TxMessage.ExtId = 0x12; // 设置扩展标示符(29 位)
  15.   TxMessage.IDE = CAN_Id_Standard; // 标准帧
  16.   TxMessage.RTR = CAN_RTR_Data; // 数据帧
  17.   TxMessage.DLC = len; // 要发送的数据长度
  18.   for(i=0;i<len;i++)
  19.                 TxMessage.Data[i] = msg[i];
  20.         mbox= CAN_Transmit(CAN1, &TxMessage);
  21.   i=0;
  22.   while((CAN_TransmitStatus(CAN1, mbox)!= CAN_TxStatus_Ok)&&(i<0xfff))i++; //等待结束
  23.    if(i>=0xfff)return 1;
  24.    return 0;
  25. }


 楼主| 一路向北lm 发表于 2020-8-31 20:05 | 显示全部楼层
CAN接收函数,采用中断方式接收
  1. //CAN接收 中断服务函数
  2. void USB_LP_CAN1_RX0_IRQHandler(void)
  3. {
  4.         CanRxMsg RxMessage;
  5.         int i=0;
  6.         CAN_Receive(CAN1, 0, &RxMessage);
  7.         for(i=0;i<8;i++)
  8.         printf("rxbuf[%d]:%d\r\n",i,RxMessage.Data[i]);
  9. }


 楼主| 一路向北lm 发表于 2020-8-31 20:06 | 显示全部楼层
main.c中添加测试代码,暂且使用回环模式进行测试,波特率设置为1M,代码和串口打印的数据如下,证明一切OK,又可以进行下一步啦!
  1. unsigned char canbuf[8];
  2. unsigned char i,res;

  3. void Delay(unsigned int t)
  4. {
  5.    unsigned int x,y;
  6.          for(x=t;x>0;x--)
  7.           for(y=1000;y>0;y--);
  8. }
  9. int main(void)
  10. {       
  11.    Uart_Config();
  12.          CAN_Config(1,0,2,1,30);  //200K 回环模式
  13.          printf("Test CAN_Mode_LoopBack!\r\n");
  14.   while(1)
  15.         {
  16.                 for(i=0;i<8;i++)
  17.                 {
  18.                    canbuf[i]=i; //填充发送缓冲区
  19.                 }
  20.      res = Can_Send_Msg(canbuf,8); //发送 8 个字节
  21.                  if(res==0 ) printf("Send OK!\r\n");
  22.                  else   printf("Send Error!\r\n");
  23.                  Delay(8000);
  24.         }
  25. }


 楼主| 一路向北lm 发表于 2020-8-31 20:06 | 显示全部楼层
测试结果:

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有账号?注册

×
 楼主| 一路向北lm 发表于 2020-8-31 20:07 | 显示全部楼层
添加定时器,为CANopen提供时钟节拍
CANopen的运行需要定时器为其提供时基,所以完成定时器的驱动也是必不可少的一步,暂且使用TIM3
 楼主| 一路向北lm 发表于 2020-8-31 20:07 | 显示全部楼层
TIM3定时器的初始化和中断函数代码如下:
  1. #include "bsp_timer.h"

  2. unsigned char timeflag;
  3. /************************************************************
  4. * 定时器计算公式:
  5. * Tout= ((arr+1)*(psc+1))/Tclk;
  6. *
  7. *  arr:  设置自动重装载寄存器周期的值
  8. *  psc:  设置时钟频率除数的预分频值
  9. *  Tclk: TIM3 的输入时钟频率(单位为 Mhz) 72M
  10. *  Tout: TIM3 溢出时间(单位为 us)  
  11. *  举例:10Khz 的计数频率,定时500ms   arr = 4999   psc = 7199
  12. *************************************************************/
  13. void Timer_Config(unsigned int arr,unsigned int psc)
  14. {
  15.    TIM_TimeBaseInitTypeDef    TIM_TimeBaseStructure;
  16.    NVIC_InitTypeDef           NVIC_InitStructure;
  17.    RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE); // 使能TIM3时钟
  18.        
  19.         //定时器 TIM3 初始化
  20.   TIM_TimeBaseStructure.TIM_Period = arr; //设置自动重装载寄存器周期的值
  21.   TIM_TimeBaseStructure.TIM_Prescaler =psc; //设置时钟频率除数的预分频值
  22.   TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1; //设置时钟分割
  23.   TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up; //TIM 向上计数
  24.   TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure); //初始化 TIM3
  25.   TIM_ITConfig(TIM3,TIM_IT_Update,ENABLE ); //允许更新中断
  26.         //中断优先级 NVIC 设置
  27.   NVIC_InitStructure.NVIC_IRQChannel = TIM3_IRQn; //TIM3 中断
  28.   NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0; //先占优先级 0 级
  29.   NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //从优先级 3 级
  30.   NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ 通道被使能
  31.   NVIC_Init(&NVIC_InitStructure); //初始化NVIC
  32.   TIM_Cmd(TIM3, ENABLE); //使能TIM3
  33. }

  34. //定时器 3 中断服务程序
  35. void TIM3_IRQHandler(void) //TIM3 中断
  36. {
  37.   if (TIM_GetITStatus(TIM3, TIM_IT_Update) != RESET) //检查 TIM3 更新中断发生与否
  38.   {
  39.    TIM_ClearITPendingBit(TIM3, TIM_IT_Update ); //清除 TIM3 更新中断标志
  40.    timeflag = 1;
  41.   }
  42. }


 楼主| 一路向北lm 发表于 2020-8-31 20:08 | 显示全部楼层
上面发送CAN报文还是使用模拟的延时函数来发送数据,现在就可以使用定时器来大摇大摆的发送数据啦!主函数测试代码如下,效果依旧如此,这一步我们也算完成啦!
  1. extern unsigned char timeflag;
  2. unsigned char canbuf[8];
  3. unsigned char i,res;

  4. int main(void)
  5. {       
  6.    Uart_Config();
  7.          Timer_Config(4999,7199); //500ms  10K
  8.          CAN_Config(1,0,2,1,30);  //200K 回环模式
  9.          printf("Test CAN_Mode_LoopBack!\r\n");
  10.          while(1)
  11.                 {
  12.                         if(timeflag == 1)
  13.                         {
  14.                                 timeflag = 0;
  15.                           for(i=0;i<8;i++)
  16.                                 {
  17.                                          canbuf[i]=i; //填充发送缓冲区
  18.                                 }
  19.                          res = Can_Send_Msg(canbuf,8); //发送 8 个字节
  20.                          if(res==0 ) printf("Send OK!\r\n");
  21.                          else   printf("Send Error!\r\n");
  22.                         }               
  23.                 }
  24. }


您需要登录后才可以回帖 登录 | 注册

本版积分规则

293

主题

3837

帖子

81

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