CanFestival移植到STM32F103

北战南征 提交于 2019-12-12 14:16:24

CanFestival移植到STM32F103

分类专栏: STM32 CANOpen

版权声明:本文为博主原创文章,遵循 CC 4.0 BY-SA 版权协议,转载请附上原文出处链接和本声明。

本文链接:https://blog.csdn.net/lushoumin/article/details/88546785

收起

1.创建工程

 

 

2.将CanFestival源码,拷贝到工程目录

 

 

3.删除其它架构和编译器的代码

查看include文件夹发现没有cortex-m3架构,因此我们这里借鉴AVR架构进行修改

将AVR文件夹重命名为STM32,并删除其它架构文件夹

打开STM32文件夹,将里面avr相关的文件删除,我们用的开发环境是MDK,因此将iar相关文件也删了

打开src文件夹,将其它架构、编译器和系统的文件给删了

 

 

4.将CanFestival文件添加进工程

添加好之后,编译出现错误,config文件中包含了很多iar相关头文件

将这些头文件删除

重新编译,依然存在错误,提示有很多函数没有定义

先解决start_and_seek_node和start_node的问题,打开def.c文件发现这两个函数定义了

其实,这是MDK开发环境的问题,不要太纠结这个问题,把inline删掉就好了

然后重新编译,还剩下三个错误canSend、getElapsedTime和setTimer没有定义。这三个接口是需要用户移植程序的时候自己进行添加的。

 

 

5.添加接口

分别创建rcc.h、rcc.c、nvic.h、nvic.c、CANOpen_can.h、CANOpen_can.c、CANOpen_timeBase.h、CANOpen_timeBase.c文件


 
  1. /**

  2. ***********************************

  3. * 文件名: nvic.h

  4. * 作者: stone

  5. * 版本: V0.1

  6. * 日期: 2018-3-29

  7. * 描述: 设置中断控制器

  8. ***********************************

  9. */

  10. #ifndef __NVIC_H_

  11. #define __NVIC_H_

  12.  
  13. /* 功能: 中断嵌套控制器配置

  14. 参数: 无

  15. 返回值:无

  16. */

  17. void nvic_config(void);

  18.  
  19. #endif


 
  1. /**

  2. ***********************************

  3. * 文件名: nvic.c

  4. * 作者: stone

  5. * 版本: V0.1

  6. * 日期: 2018-3-29

  7. * 描述: 设置中断控制器

  8. ***********************************

  9. */

  10. #include "stm32f10x.h"

  11. #include "nvic.h"

  12.  
  13. /* 功能: 中断嵌套控制器配置

  14. 参数: 无

  15. 返回值:无

  16. */

  17. void nvic_config(void)

  18. {

  19. /* 选择中断分组4 */

  20. NVIC_PriorityGroupConfig(NVIC_PriorityGroup_4);

  21. }


 
  1. /**

  2. ***********************************

  3. * 文件名:rcc.h

  4. * 作者: stone

  5. * 版本: V0.1

  6. * 日期: 2018-3-29

  7. * 描述: 配置时钟源

  8. ***********************************

  9. */

  10. #ifndef __RCC_H_

  11. #define __RCC_H_

  12.  
  13. /* 功能: RCC时钟配置

  14. 参数: 无

  15. 返回值:无

  16. */

  17. void rcc_config(void);

  18.  
  19. #endif


 
  1. /**

  2. ***********************************

  3. * 文件名: rcc.c

  4. * 作者: stone

  5. * 版本: V0.1

  6. * 日期: 2018-3-29

  7. * 描述: 配置时钟源

  8. ***********************************

  9. */

  10. #include "stm32f10x.h"

  11. #include "stm32f10x_flash.h"

  12. #include "rcc.h"

  13.  
  14. /* 功能: RCC时钟配置

  15. 参数: 无

  16. 返回值:无

  17. */

  18. void rcc_config(void)

  19. {

  20. ErrorStatus HSEStartUpStatus;

  21.  
  22. /* RCC寄存器设置为默认配置 */

  23. RCC_DeInit();

  24.  
  25. /* 打开外部高速时钟 */

  26. RCC_HSEConfig(RCC_HSE_ON);

  27. /* 等待外部高速时钟稳定 */

  28. HSEStartUpStatus = RCC_WaitForHSEStartUp();

  29. if(HSEStartUpStatus == SUCCESS)

  30. {

  31. /* 设置HCLK = SYSCLK */

  32. RCC_HCLKConfig(RCC_SYSCLK_Div1);

  33. /* 设置PCLK2 = HCLK */

  34. RCC_PCLK2Config(RCC_HCLK_Div1);

  35. /* 设置PCLK1 = HCLK / 2 */

  36. RCC_PCLK1Config(RCC_HCLK_Div2);

  37.  
  38. /* 设置FLASH代码延时 */

  39. FLASH_SetLatency(FLASH_Latency_2);

  40. /* 使能预取址缓存 */

  41. FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);

  42.  
  43. /* 设置PLL时钟源为HSE倍频9 72MHz */

  44. RCC_PLLConfig(RCC_PLLSource_HSE_Div1, RCC_PLLMul_9);

  45. /* 使能PLL */

  46. RCC_PLLCmd(ENABLE);

  47. /* 等待PLL稳定 */

  48. while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);

  49.  
  50. /* 设置PLL为系统时钟源 */

  51. RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);

  52. /* 等待系统时钟源切换到PLL */

  53. while(RCC_GetSYSCLKSource() != 0x08);

  54.  
  55. /* 设置系统节拍器时钟源为FCLK */

  56. SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK);

  57. }

  58. }


 
  1. /**

  2. ***********************************

  3. * 文件名: CANOpen_timeBase.h

  4. * 作者: stone

  5. * 版本: V0.1

  6. * 日期: 2018-3-29

  7. * 描述: CANOPEN底层定时器接口文件

  8. ***********************************

  9. */

  10. #ifndef __CANOPEN_TIMEBASE_H_

  11. #define __CANOPEN_TIMEBASE_H_

  12.  
  13. /* 功能: canopen时基配置

  14. 参数: 无

  15. 返回值:无

  16. */

  17. void canopen_timebase_config(void);

  18.  
  19. #endif


 
  1. /**

  2. ***********************************

  3. * 文件名: CANOpen_timeBase.c

  4. * 作者: stone

  5. * 版本: V0.1

  6. * 日期: 2018-3-29

  7. * 描述: CANOPEN底层定时器接口文件

  8. ***********************************

  9. */

  10. #include "stm32f10x.h"

  11. #include "canfestival.h"

  12. #include "CANOpen_timeBase.h"

  13.  
  14. /* 功能: 定时器配置

  15. 参数: 无

  16. 返回值:无

  17. */

  18. static void timer_config(void)

  19. {

  20. TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;

  21.  
  22. /* 允许TIM2的时钟 */

  23. RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);

  24.  
  25. /* 将定时器2寄存器设为初始值 */

  26. TIM_DeInit(TIM2);

  27.  
  28. /* 设置定时器2由内部时钟 */

  29. TIM_InternalClockConfig(TIM2);

  30.  
  31. /* 预分频值 */

  32. TIM_TimeBaseStructure.TIM_Prescaler = 72 - 1;

  33. /* 时钟分割 */

  34. TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;

  35. /* 向上计数 */

  36. TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;

  37. /* 自动重载值 */

  38. TIM_TimeBaseStructure.TIM_Period = 65535 - 1;

  39. /* 初始化定时器2 */

  40. TIM_TimeBaseInit(TIM2, &TIM_TimeBaseStructure);

  41.  
  42. /* 清除溢出中断标志 */

  43. TIM_ClearFlag(TIM2, TIM_FLAG_Update);

  44.  
  45. /* 禁止ARR预装载缓冲器 */

  46. TIM_ARRPreloadConfig(TIM2, DISABLE);

  47.  
  48. /* 开启TIM2的中断 */

  49. TIM_ITConfig(TIM2, TIM_IT_Update, ENABLE);

  50.  
  51. /* 开启定时器2 */

  52. TIM_Cmd(TIM2, ENABLE);

  53. }

  54.  
  55. /* 功能: 中断配置

  56. 参数: 无

  57. 返回值:无

  58. */

  59. static void nvic_config(void)

  60. {

  61. NVIC_InitTypeDef NVIC_InitStructure;

  62.  
  63. /* 选择TIM2的中断通道 */

  64. NVIC_InitStructure.NVIC_IRQChannel = TIM2_IRQn;

  65. /* 抢占式中断优先级设置为2 */

  66. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;

  67. /* 响应式中断优先级设置为2 */

  68. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;

  69. /* 使能中断 */

  70. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  71. /* 中断初始化 */

  72. NVIC_Init(&NVIC_InitStructure);

  73. }

  74.  
  75. /* 功能: canopen时基配置

  76. 参数: 无

  77. 返回值:无

  78. */

  79. void canopen_timebase_config(void)

  80. {

  81. /* 定时器配置 */

  82. timer_config();

  83.  
  84. /* 中断配置 */

  85. nvic_config();

  86. }

  87.  
  88. /* 功能: 设置定时器触发时间

  89. 参数: 定时器触发时间

  90. 返回值:无

  91. */

  92. void setTimer(TIMEVAL value)

  93. {

  94. if(value - 1 == 0)

  95. TIM2->ARR = 1;

  96. else

  97. TIM2->ARR = value - 1;

  98.  
  99. TIM2->CNT = 0;

  100. }

  101.  
  102. /* 功能: 获取上次触发到现在的流逝时间

  103. 参数: 无

  104. 返回值:获取计数器值

  105. */

  106. TIMEVAL getElapsedTime(void)

  107. {

  108. return TIM2->CNT;

  109. }

  110.  
  111. /* 定时器2中断向量 */

  112. void TIM2_IRQHandler(void)

  113. {

  114. /* 定时器2溢出标志位 */

  115. if(TIM_GetITStatus(TIM2, TIM_IT_Update) != RESET)

  116. {

  117. /* 定时器2清除溢出标志位 */

  118. TIM_ClearITPendingBit(TIM2 , TIM_FLAG_Update);

  119.  
  120. TimeDispatch();

  121. }

  122. }


 
  1. /**

  2. ***********************************

  3. * 文件名: CANOpen_can.h

  4. * 作者: stone

  5. * 版本: V0.1

  6. * 日期: 2018-3-29

  7. * 描述: CANOPEN协议底层总线接口

  8. ***********************************

  9. */

  10. #ifndef __CANOPEN_CAN_H_

  11. #define __CANOPEN_CAN_H_

  12.  
  13. /* 功能: can总线配置

  14. 参数: 无

  15. 返回值:无

  16. */

  17. void CANOpen_can_config(void);

  18.  
  19. #endif


 
  1. /**

  2. ***********************************

  3. * 文件名: CANOpen_can.c

  4. * 作者: stone

  5. * 版本: V0.1

  6. * 日期: 2018-3-29

  7. * 描述: CANOPEN协议底层总线接口

  8. ***********************************

  9. */

  10. #include "stm32f10x.h"

  11. #include "CANOpen_can.h"

  12. #include "canfestival.h"

  13.  
  14. /* CANOPEN字典 */

  15. extern CO_Data masterObjdict_Data;

  16.  
  17. /* 功能: GPIO配置

  18. 参数: 无

  19. 返回值:无

  20. */

  21. static void gpio_config(void)

  22. {

  23. GPIO_InitTypeDef GPIO_InitStructure;

  24.  
  25. /* 开启GPIO时钟 */

  26. RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_AFIO, ENABLE);

  27.  
  28. /* CAN_RX */

  29. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_11;

  30. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;

  31. GPIO_Init(GPIOA, &GPIO_InitStructure);

  32.  
  33. /* CAN_TX */

  34. GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12;

  35. GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;

  36. GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

  37. GPIO_Init(GPIOA, &GPIO_InitStructure);

  38. }

  39.  
  40. /* 功能: 中断嵌套控制器配置

  41. 参数: 无

  42. 返回值:无

  43. */

  44. static void nvic_config(void)

  45. {

  46. NVIC_InitTypeDef NVIC_InitStructure;

  47.  
  48. /* 设置CAN接收中断,先占优先级2,从站优先级2 */

  49. NVIC_InitStructure.NVIC_IRQChannel = USB_LP_CAN1_RX0_IRQn;

  50. NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 2;

  51. NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;

  52. NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

  53.  
  54. /* 初始化中断 */

  55. NVIC_Init(&NVIC_InitStructure);

  56. }

  57.  
  58. /* 功能: CAN总线过滤器配置

  59. 参数: 无

  60. 返回值:无

  61. */

  62. static void can_filter_config(void)

  63. {

  64. CAN_FilterInitTypeDef CAN_FilterInitStructure;

  65.  
  66. /* 配置过滤器0组,配置成标准标识符且低7位都为0时接受 */

  67. CAN_FilterInitStructure.CAN_FilterNumber = 0; /* 设置过滤器组0 */

  68. CAN_FilterInitStructure.CAN_FilterMode = CAN_FilterMode_IdMask; /* 屏蔽模式 */

  69. CAN_FilterInitStructure.CAN_FilterScale = CAN_FilterScale_32bit; /* 32位模式 */

  70. CAN_FilterInitStructure.CAN_FilterMaskIdHigh = 0x0000; /* 在CANOpen中标准标识符的低7位表示节点ID */

  71. CAN_FilterInitStructure.CAN_FilterMaskIdLow = 0x0004; /* 在CANOpen中只用标准标识符,数据帧/远程帧都有 */

  72. CAN_FilterInitStructure.CAN_FilterIdHigh = 0x0000; /* 主节点ID为0 */

  73. CAN_FilterInitStructure.CAN_FilterIdLow = 0x0000; /* 标准帧 */

  74. CAN_FilterInitStructure.CAN_FilterFIFOAssignment = CAN_Filter_FIFO0; /* 过滤器关联到FIFO0 */

  75. CAN_FilterInitStructure.CAN_FilterActivation = ENABLE; /* 使能过滤器 */

  76. CAN_FilterInit(&CAN_FilterInitStructure);

  77. }

  78.  
  79. /* 功能: can总线配置

  80. 参数: 无

  81. 返回值:无

  82. */

  83. void CANOpen_can_config(void)

  84. {

  85. CAN_InitTypeDef CAN_InitStructure;

  86.  
  87. /* 配置IO */

  88. gpio_config();

  89.  
  90. /* 中断嵌套控制器配置 */

  91. nvic_config();

  92.  
  93. /* 配置CAN总线时钟 */

  94. RCC_APB1PeriphClockCmd(RCC_APB1Periph_CAN1, ENABLE);

  95.  
  96. /* CAN1默认参数 */

  97. CAN_DeInit(CAN1);

  98.  
  99. /* 将结构体填入默认参数 */

  100. CAN_StructInit(&CAN_InitStructure);

  101.  
  102. /* 关闭时间触发模式 */

  103. CAN_InitStructure.CAN_TTCM = DISABLE;

  104. /* 关闭自动离线管理 */

  105. CAN_InitStructure.CAN_ABOM = ENABLE;

  106. /* 关闭自动唤醒 */

  107. CAN_InitStructure.CAN_AWUM = ENABLE;

  108. /* 自动重传 */

  109. CAN_InitStructure.CAN_NART = DISABLE;

  110. /* 禁止FIFO溢出时覆盖原报文 */

  111. CAN_InitStructure.CAN_RFLM = DISABLE;

  112. /* 关闭优先级取决于ID */

  113. CAN_InitStructure.CAN_TXFP = DISABLE;

  114. /* 正常模式 */

  115. CAN_InitStructure.CAN_Mode = CAN_Mode_Normal;

  116.  
  117. /* 设置波特率:36MHz/9/(2+1+1)=1mbps */

  118. CAN_InitStructure.CAN_SJW = CAN_SJW_1tq;

  119. CAN_InitStructure.CAN_BS1 = CAN_BS1_2tq;

  120. CAN_InitStructure.CAN_BS2 = CAN_BS2_1tq;

  121. CAN_InitStructure.CAN_Prescaler = 9;

  122.  
  123. /* 初始化CAN总线 */

  124. CAN_Init(CAN1, &CAN_InitStructure);

  125.  
  126. /* CAN总线过滤器配置 */

  127. can_filter_config();

  128.  
  129. /* 接收挂起中断 */

  130. CAN_ITConfig(CAN1, CAN_IT_FMP0, ENABLE);

  131. }

  132.  
  133. /* can总线接收中断回调函数 */

  134. void USB_LP_CAN1_RX0_IRQHandler(void)

  135. {

  136. CanRxMsg message;

  137. Message Rx_Message;

  138.  
  139. /* 接收消息 */

  140. CAN_Receive(CAN1, CAN_FIFO0, &message);

  141.  
  142. /* 组装canopen数据包 */

  143. Rx_Message.cob_id = message.StdId; /* 功能码和节点ID */

  144. Rx_Message.rtr = (message.RTR == CAN_RTR_DATA) ? 0 : 1; /* 标识符类型 */

  145. Rx_Message.len = message.DLC; /* 数据包长度 */

  146. memcpy(Rx_Message.data, message.Data, message.DLC); /* 数据 */

  147.  
  148. /* canopen数据包分配处理函数 */

  149. canDispatch(&masterObjdict_Data, &Rx_Message);

  150. }

  151.  
  152. /* 功能: CAN发送数据函数

  153. 参数: notused can总线端口

  154. message canopen数据包

  155. 返回值: 0 成功

  156. 1 失败

  157. */

  158. uint8_t canSend(CAN_PORT notused, Message *message)

  159. {

  160. uint32_t i = 0xFFFFFF;

  161. CanTxMsg TxMessage;

  162. uint8_t TransmitMailbox = 0;

  163.  
  164. /* 组装CAN数据包 */

  165. TxMessage.DLC = message->len; /* 数据长度 */

  166. memcpy(TxMessage.Data, message->data, message->len); /* 数据 */

  167. TxMessage.IDE = CAN_ID_STD; /* 标准ID */

  168. TxMessage.StdId = message->cob_id; /* 标识符 */

  169. TxMessage.RTR = (message->rtr == CAN_RTR_DATA) ? 0 : 2; /* 数据帧 */

  170.  
  171. /* 发送数据包 */

  172. TransmitMailbox = CAN_Transmit(CAN1, &TxMessage);

  173. /* 等待发送成功 */

  174. while((CAN_TransmitStatus(CAN1, TransmitMailbox) != CANTXOK) && --i);

  175.  
  176. /* 成功0 超时1 */

  177. return (i != 0) ? 0 : 1;

  178. }


 
  1. /**

  2. ***********************************

  3. * 文件名: main.c

  4. * 作者: stone

  5. * 版本: V0.1

  6. * 日期: 2018-3-29

  7. * 描述: 主文件

  8. ***********************************

  9. */

  10. #include "stm32f10x.h"

  11. #include "rcc.h"

  12. #include "nvic.h"

  13. #include "CANOpen_timeBase.h"

  14. #include "CANOpen_can.h"

  15.  
  16. /* 主函数 */

  17. int main(void)

  18. {

  19. /* 时钟配置 */

  20. rcc_config();

  21.  
  22. /* 中断嵌套控制器配置 */

  23. nvic_config();

  24.  
  25. /* canopen时基配置 */

  26. canopen_timebase_config();

  27.  
  28. /* can总线配置 */

  29. CANOpen_can_config();

  30.  
  31. while(1)

  32. {

  33.  
  34. }

  35. }

添加好之后,重新编译,提示没有定义CANOpen字典

 

 

6.创建CANOpen字典

打开objdictedit,创建字典

分别得到masterObjdict.h和masterObjdict.c文件

 

 

7.将字典文件添加进工程

重新编译,0错误,0警告

 

8.修改配置

按照CANOpen_timeBase.c的配置,定时器单位计数为1us。打开timerscfg.h。

AVR的例程定时器的单位计数时间为8us,我们这里做一个修改。

 

9.协议栈移植工作完成。下面要考虑的就是字典配置和协议栈使用的问题了。

易学教程内所有资源均来自网络或用户发布的内容,如有违反法律规定的内容欢迎反馈
该文章没有解决你所遇到的问题?点击提问,说说你的问题,让更多的人一起探讨吧!