STM32F407CANopenmaster
STM32F407控制CANopen从站
前面我有篇文章——CAN&CANopen,讲清楚了CAN通讯是怎么一回事,没有举具体的例子。这篇文章我就用一个具体的例子,让大家更好的理解具体是怎么用。
硬件准备:STM32F407ZGT6开发板+ IXXAT CAN卡+支持CANopen通讯的驱动器
目标效果:STM32通过CAN口控制驱动器完成PPM和CSP模式的运动控制,对PPM和CSP模式没有概念的参我的另一篇文章——我理解的运动控制系统,里面有详细介绍。
首先,完成STM32的基本配置,我用的cubeMX,这个弄起来快。
第一步,系统时钟配置,注意红框标记的地方,我的HSE是8Mhz的,根据你的开发板修改。F407支持的最高频率是168Mhz,不可超过,关于时钟配置的细节可以参官方的参考手册,这里不展开讲了。
第二步,配置HSE为陶瓷晶振。
第三步,配置下载和调试接口。
第四步,CAN控制配置,我设置的波特率是1Mbps,这也是CAN总线支持的最高通讯速率。CAN总线上的所有设备波特率必须一样,这是能通讯的前提,不然解出来的都是错误帧。还要使能CAN的接收中断。
第五步,配置USART,这个是为了调试方便和接收控制命令用的。
使能USART的中断
USART的发送和接收都是DMA传输,网传接收和发送的DMA不可以同时使用,实测可以解决,DMA非常方便。
第六步,配置TIMER,这个是CSP模式定时发送数据用的。总线是168Mhz的,168-1的预分频之后就是1Mhz,向上计数10000就是10ms。
需要开启TIM6的中断
第七步,工程配置,我用的KEIL,在工具链中选择MDK-ARM,版本V5。
代码生成配置,选择所有已用的库到工程。每个外设配置生成单独的.c/.h文件,方便查看和管理。再次生产代码前先备份。再次生成前保留用户代码,这个一定要选,并且还要写在用户代码区,不然重生成后代码都被删除了。不再需要的配置再重生成代码的时候删除,这个可选,文件少编译的更快。把所有没有使用的引脚都设置为模拟模式,这样可以减少功耗。
第八步,点击GENERATE CODE生成代码,然后用你的IDE打开工程。
到这里cubeMX的配置就已经完成了,接下来就直接开始在IDE中上代码了。
CAN控制器的初始化中没有配置CAN的滤波器,这个需要我们手动配置。代码放在can.c的void MX_CAN1_Init(void)函数中,如下:
/* USER CODE BEGIN CAN1_Init 2 */
CAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterActivation = CAN_FILTER_ENABLE;
sFilterConfig.FilterBank = 0;
sFilterConfig.FilterFIFOAssignment = CAN_FILTER_FIFO0;
sFilterConfig.FilterIdHigh = 0x0000;
sFilterConfig.FilterIdLow = 0x0000;
sFilterConfig.FilterMaskIdHigh = 0x0000;
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK;
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT;
sFilterConfig.SlaveStartFilterBank = 14;
if(HAL_CAN_ConfigFilter(&hcan1,&sFilterConfig))
{
Error_Handler();
}
HAL_CAN_ActivateNotification(&hcan1,CAN_IT_RX_FIFO0_MSG_PENDING);
/* USER CODE END CAN1_Init 2 */
这里说下滤波器配置的两种模式,一个是列表模式,一个是掩码模式。列表模式就是ID在列表中的报文可以通过,其他的都不能通过,不在列表中的都不能通过,这个比较好理解。掩码模式就是掩码寄存器中对应bit为1的表示关心,报文中ID的对应bit位也必须为1;掩码寄存器中对应bit为0的表示不关心,报文ID的对应bit位可为0或1。如现在配置的都是0x0000,表示任何ID的数据都接收,因为现在是把STM32做CANopen的master,需要接收总线上的所有数据。最后一行HAL_CAN_ActivateNotification是为了使能接收邮箱的中断。
接下来就是初始化各个外设,这里遇到两个坑,第一个是DMA的初始化要在使用DMA的外设之前,不然就不会成功。第二个是使能定时器中断的时候要先停止定时器中断,追溯源代码发现是函数有个状态没复位,停止中断的函数里面将这个状态复位了。这个可能与固件版本有关,我这个V1.27.0是这样,STM32G474的库也不需要这样操作。USART的DMA接收我用了扩展函数HAL_UARTEx_ReceiveToIdle_DMA,这个非常方便。
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_DMA_Init();
MX_USART1_UART_Init();
MX_TIM6_Init();
MX_CAN1_Init();
/* USER CODE BEGIN 2 */
HAL_TIM_Base_Start(&htim6);
HAL_TIM_Base_Stop_IT(&htim6); // stop_IT function is necessary ,for reset state ,else TIMER won"t work
HAL_TIM_Base_Start_IT(&htim6);
__HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
HAL_UARTEx_ReceiveToIdle_DMA(&huart1,uart_rx_data,uart_rx_max);
__HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
HAL_CAN_Start(&hcan1);
/* USER CODE END 2 */
到这里,主要的配置就已经完成了,接下来就是细化各个功能函数了,不再详细介绍,我直接把main.c的代码全部复制到文章末尾了,可以直接复制去测试和研究。
本文只是抛砖引玉的介绍了怎样配置和使用STM32F407的CAN控制器,怎样发送CAN报文去控制从站驱动器,没有涉及到整个CANopen主站的协议。如网络管理,错误处理这些都没有做,对于特定的项目我觉得可以根据需要去设计功能,不一定要实现协议的全部细节。后续有时间再弄个完整的CANopen master协议栈。关于驱动器调试和配置部分这里没有涉及,参见对于驱动器厂家的调试和使用说明即可。文章中比较陌生的名词,可以参见我的另外两篇文章——我理解的运动控制系统和CAN&CANopen。
CAN与CANOPEN - Let"sDoSomething - 云海天 (cnblogs.com)
我理解的运动控制系统 - Let"sDoSomething - 云海天 (cnblogs.com)
1/* USER CODE BEGIN Header */2/**
3 ******************************************************************************
4 * @file : main.c
5 * @brief : Main program body
6 ******************************************************************************
7 * @attention
8 *
9 * Copyright (c) 2022 STMicroelectronics.
10 * All rights reserved.
11 *
12 * This software is licensed under terms that can be found in the LICENSE file
13 * in the root directory of this software component.
14 * If no LICENSE file comes with this software, it is provided AS-IS.
15 *
16 ******************************************************************************
17*/
18/* USER CODE END Header */
19/* Includes ------------------------------------------------------------------*/
20 #include "main.h"
21 #include "can.h"
22 #include "dma.h"
23 #include "tim.h"
24 #include "usart.h"
25 #include "gpio.h"
26
27/* Private includes ----------------------------------------------------------*/
28/* USER CODE BEGIN Includes */
29 #include "stdio.h"
30 #include "string.h"
31/* USER CODE END Includes */
32
33/* Private typedef -----------------------------------------------------------*/
34/* USER CODE BEGIN PTD */
35
36/* USER CODE END PTD */
37
38/* Private define ------------------------------------------------------------*/
39/* USER CODE BEGIN PD */
40/* USER CODE END PD */
41
42/* Private macro -------------------------------------------------------------*/
43/* USER CODE BEGIN PM */
44
45/* USER CODE END PM */
46
47/* Private variables ---------------------------------------------------------*/
48
49/* USER CODE BEGIN PV */
50 uint8_t testData[]={0x00,0x01,0x02,0x03,0x04,0x05,0x06,0x07};
51//CAN transmit data field, 8 bytes
52 uint8_t object_data[8]={0};
53//CSP mode conuts, work until CSP_num > CSP_MAX_NUM
54 uint8_t CSP_num = 0;
55//csp mode max number, generate CSP_pos relatively
56 uint8_t CSP_MAX_NUM = 61;
57//CSP_flag, 0 means unused/finished, 1 means CSP is working
58 uint8_t CSP_flag = 0;
59//CAN transmit mailbox
60 uint32_t TxMailBox = CAN_TX_MAILBOX0;
61//CAN transmit frame struct
62 CAN_TxHeaderTypeDef TxHeader;
63//for CAN communication store data
64 uint8_t RxData[] = {0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00};
65//store CAN receive data temporarily, convert byte to int used
66 uint8_t can_Frame_DataField[4] ={0};
67//store CAN communication PDO data temporarily ,length could be longer/shorter ,upon PDO length
68 uint8_t PDO_DataField[4] = {0};
69//CAN Receive frame struct
70 CAN_RxHeaderTypeDef RxHeader;
71//CAN receive flag ,set by can_receive interrupt ,reset by other function
72 uint8_t can_receive_flag = 0;
73//store uart receive data
74 uint8_t uart_rx_data[]={0};
75//max uart receive length
76 uint16_t uart_rx_max = 255;
77//store result for ConvertInttoFourByte function
78 uint8_t byte_value[4] = {0};
79//store CSP mode position points
80 int32_t CSP_Pos[61]={0};
81//CSP mode acceleration, larger and faster , smaller and slower
82 uint32_t acc = 5;
83
84/* USER CODE END PV */
85
86/* Private function prototypes -----------------------------------------------*/
87void SystemClock_Config(void);
88/* USER CODE BEGIN PFP */
89void CAN_sendTxMessage(uint32_t std_id,uint32_t length,uint8_t data[]);
90void ConvertIntTo4Byte(int32_t source);
91 int32_t ConvertByteToInt(uint8_t *byte_source);
92void do_a_PPM_Motion();
93void do_a_CSP_Motion();
94void RPDO1_Mapping();
95
96/* USER CODE END PFP */
97
98/* Private user code ---------------------------------------------------------*/
99/* USER CODE BEGIN 0 */
100
101/* USER CODE END 0 */
102
103/**
104 * @brief The application entry point.
105 * @retval int
106*/
107int main(void)
108{
109/* USER CODE BEGIN 1 */
110
111/* USER CODE END 1 */
112
113/* MCU Configuration--------------------------------------------------------*/
114
115/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
116 HAL_Init();
117
118/* USER CODE BEGIN Init */
119
120/* USER CODE END Init */
121
122/* Configure the system clock */
123 SystemClock_Config();
124
125/* USER CODE BEGIN SysInit */
126
127/* USER CODE END SysInit */
128/* Initialize all configured peripherals */
129 MX_GPIO_Init();
130 MX_DMA_Init();
131 MX_USART1_UART_Init();
132
133 MX_TIM6_Init();
134 MX_CAN1_Init();
135/* USER CODE BEGIN 2 */
136 HAL_TIM_Base_Start(&htim6);
137 HAL_TIM_Base_Stop_IT(&htim6); // stop_IT function is necessary ,for reset state ,else TIMER won"t work
138 HAL_TIM_Base_Start_IT(&htim6);
139
140 __HAL_UART_ENABLE_IT(&huart1,UART_IT_IDLE);
141 HAL_UARTEx_ReceiveToIdle_DMA(&huart1,uart_rx_data,uart_rx_max);
142 __HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
143
144 HAL_CAN_Start(&hcan1);
145
146 HAL_Delay(50); //delay would be necessary ,shorter time is also OK
147
148 printf("This is CAN communication test program!
");
149 printf("After power up!Send 1 to activate PPM mode or send 2 to CSP mode
");
150 RPDO1_Mapping();
151 HAL_Delay(10);
152
153/* USER CODE END 2 */
154
155/* Infinite loop */
156/* USER CODE BEGIN WHILE */
157while (1)
158 {
159/* USER CODE END WHILE */
160
161/* USER CODE BEGIN 3 */
162 HAL_Delay(500);
163 HAL_GPIO_TogglePin(GPIOE,GPIO_PIN_3);
164
165if(1 == uart_rx_data[0])
166 { printf("PPM TEST
");
167 do_a_PPM_Motion();
168 uart_rx_data[0] = 0;
169 }
170elseif(2 == uart_rx_data[0])
171 { printf("CSP TEST
");
172//initiate CSP mode pos array
173for(int i=0;i<CSP_MAX_NUM;i++)
174 {
175//means explanation: physic formula S= 1/2*acc*(t*t)
176// S= 1/2*a*t*t a=100, acceleration 30points ,dec 30 points
177// Vmax= 30*a = 30*100 = 3000
178if(i<=30)
179 CSP_Pos[i] = 0.5*acc*i*i; // S= 1/2*a*t*t a=100,
180else
181 CSP_Pos[i] = CSP_Pos[i-1]+acc*(CSP_MAX_NUM/2)-0.5*acc*(2*(i - CSP_MAX_NUM/2)-1);
182 }
183 do_a_CSP_Motion();
184 uart_rx_data[0] = 0;
185 }
186
187 }
188/* USER CODE END 3 */
189}
190
191/**
192 * @brief System Clock Configuration
193 * @retval None
194*/
195void SystemClock_Config(void)
196{
197 RCC_OscInitTypeDef RCC_OscInitStruct = {0};
198 RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
199
200/** Configure the main internal regulator output voltage
201*/
202 __HAL_RCC_PWR_CLK_ENABLE();
203 __HAL_PWR_VOLTAGESCALING_CONFIG(PWR_REGULATOR_VOLTAGE_SCALE1);
204
205/** Initializes the RCC Oscillators according to the specified parameters
206 * in the RCC_OscInitTypeDef structure.
207*/
208 RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
209 RCC_OscInitStruct.HSEState = RCC_HSE_ON;
210 RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
211 RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
212 RCC_OscInitStruct.PLL.PLLM = 4;
213 RCC_OscInitStruct.PLL.PLLN = 168;
214 RCC_OscInitStruct.PLL.PLLP = RCC_PLLP_DIV2;
215 RCC_OscInitStruct.PLL.PLLQ = 4;
216if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
217 {
218 Error_Handler();
219 }
220
221/** Initializes the CPU, AHB and APB buses clocks
222*/
223 RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
224 |RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
225 RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
226 RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
227 RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV4;
228 RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV2;
229
230if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
231 {
232 Error_Handler();
233 }
234}
235
236/* USER CODE BEGIN 4 */
237void do_a_CSP_Motion()
238{
239//steps 1. disable motor, write 0x06 to object 0x6040
240// 2. chang mode to CSP, write 0x08 to object 0x6060
241// 3. check mode is CSP, read 0x6061
242// 4. set CSP cycle-time, write 0x32 to object 0x6060,unit is ms
243// 5. enable motor, write 0x0F to object 0x6040
244// 6. check motor is enabled, read 0x6041
245// 7. read current position, read 0x607A
246// 8. CPS_Pos[]+current position as final target position
247// 9. start remote node
248// 10. send target position by PDO and follow SYNC command 0x80
249// 11. CSP motion finished
250//
251//steps 1. disable motor, write 0x06 to object 0x6040
252 object_data[0]=0x2B;object_data[1]=0x40;object_data[2]=0x60;object_data[3]=0x00;
253 object_data[4]=0x06;object_data[5]=0x00;object_data[6]=0x00;object_data[7]=0x00;
254 can_receive_flag = 0;
255 CAN_sendTxMessage(0x601,8,object_data);
256 HAL_Delay(1); //HAL_DELAY() delay 1ms is necessary, else will stick here
257while(1 != can_receive_flag)
258 {;} //HAL_DELAY() delay 1ms is necessary, else will stick here
259// 2. chang mode to CSP, write 0x08 to object 0x6060
260 object_data[0]=0x2F;object_data[1]=0x60;object_data[2]=0x60;object_data[3]=0x00;
261 object_data[4]=0x08;object_data[5]=0x00;object_data[6]=0x00;object_data[7]=0x00;
262 can_receive_flag = 0;
263 CAN_sendTxMessage(0x601,8,object_data);
264 HAL_Delay(1);
265while(1 != can_receive_flag)
266 {;}
267// 3. check mode is CSP, read 0x6061
268 object_data[0]=0x40;object_data[1]=0x61;object_data[2]=0x60;object_data[3]=0x00;
269 object_data[4]=0x00;object_data[5]=0x00;object_data[6]=0x00;object_data[7]=0x00;
270 can_receive_flag = 0;
271 CAN_sendTxMessage(0x601,8,object_data);
272 HAL_Delay(1);
273while(1 != can_receive_flag)
274 {;}
275if(8 != RxData[4]) //8 means CSP mode
276 printf("Set CSP mode failed
");
277// 4. set CSP cycle-time, write 0x32 to object 0x6060,unit is ms
278 object_data[0]=0x2F;object_data[1]=0xC2;object_data[2]=0x60;object_data[3]=0x00;
279 object_data[4]=0x32;object_data[5]=0x00;object_data[6]=0x00;object_data[7]=0x00;
280 can_receive_flag = 0;
281 CAN_sendTxMessage(0x601,8,object_data);
282 HAL_Delay(1);
283while(1 != can_receive_flag)
284 {;}
285// 5. enable motor, write 0x0F to object 0x6040
286 object_data[0]=0x2B;object_data[1]=0x40;object_data[2]=0x60;object_data[3]=0x00;
287 object_data[4]=0x0F;object_data[5]=0x00;object_data[6]=0x00;object_data[7]=0x00;
288 can_receive_flag = 0;
289 CAN_sendTxMessage(0x601,8,object_data);
290 HAL_Delay(1);
291while(1 != can_receive_flag)
292 {;}
293// 6. check motor is enabled, read 0x6041
294 object_data[0]=0x40;object_data[1]=0x41;object_data[2]=0x60;object_data[3]=0x00;
295 object_data[4]=0x00;object_data[5]=0x00;object_data[6]=0x00;object_data[7]=0x00;
296 can_receive_flag = 0;
297 CAN_sendTxMessage(0x601,8,object_data);
298 HAL_Delay(10);
299while(1 != can_receive_flag)
300 {;}
301if((RxData[4] & 0x04)) //0x04 means drive is operation enabled
302 printf("CSP mode enable failed
");
303// 7. read current position, read 0x607A
304 object_data[0]=0x40;object_data[1]=0x64;object_data[2]=0x60;object_data[3]=0x00;
305 object_data[4]=0x00;object_data[5]=0x00;object_data[6]=0x00;object_data[7]=0x00;
306 can_receive_flag = 0;
307 CAN_sendTxMessage(0x601,8,object_data);
308 HAL_Delay(1);
309while(1 != can_receive_flag)
310 {;}
311for(int i=0;i<4;i++)
312 can_Frame_DataField[i]=RxData[i+4];
313 int32_t current_Pos;
314 current_Pos = ConvertByteToInt(can_Frame_DataField);
315 printf("current pos is %d
",current_Pos);
316// 8. CPS_Pos[]+current position as final target position
317for(int i=0;i<61;i++)
318 CSP_Pos[i] = CSP_Pos[i] + current_Pos;
319// 9. start remote node
320 object_data[0]=0x01;object_data[1]=0x00;
321 can_receive_flag = 0;
322 CAN_sendTxMessage(0x00,2,object_data);
323 HAL_Delay(20);
324
325// 10. send target position by PDO and follow SYNC command 0x80
326 CSP_flag = 1;
327 CSP_num = 0;
328}
329//do_a_PPM_Motion
330void do_a_PPM_Motion()
331{
332//steps 1. disable motor, write 0x06 to object 0x6040
333// 2. chang mode to PPM, write 0x01 to object 0x6060
334// 3. check mode is PPM, read 0x6061
335// 4. enable motor, write 0x0F to object 0x6040
336// 5. check motor is enabled, read 0x6041
337// 6. set profile velocity, write 0x6081
338// 7. read current position, read 0x6064
339// 8. add 5000 counts on current position as target position,write 0x607A
340// 9. start motion, write 0x0F to object 0x6040
341// 10. motion end
342//steps 1. disable motor, write 0x06 to object 0x6040
343 printf("flag1 %d
",can_receive_flag);
344 object_data[0]=0x2B;object_data[1]=0x40;object_data[2]=0x60;object_data[3]=0x00;
345 object_data[4]=0x06;object_data[5]=0x00;object_data[6]=0x00;object_data[7]=0x00;
346 can_receive_flag = 0;
347 CAN_sendTxMessage(0x601,8,object_data);
348 HAL_Delay(1); //HAL_DELAY() delay 1ms is necessary, else will stick here
349while(1 != can_receive_flag)
350 {;} //HAL_DELAY() delay 1ms is necessary, else will stick here
351// 2. chang mode to PPM, write 0x01 to object 0x6060
352 printf("flag2 %d
",can_receive_flag);
353 object_data[0]=0x2F;object_data[1]=0x60;object_data[2]=0x60;object_data[3]=0x00;
354 object_data[4]=0x01;object_data[5]=0x00;object_data[6]=0x00;object_data[7]=0x00;
355 can_receive_flag = 0;
356 CAN_sendTxMessage(0x601,8,object_data);
357 HAL_Delay(1);
358while(1 != can_receive_flag)
359 {;}
360// 3. check mode is PPM, read 0x6061
361 printf("flag3 %d
",can_receive_flag);
362 object_data[0]=0x40;object_data[1]=0x61;object_data[2]=0x60;object_data[3]=0x00;
363 object_data[4]=0x00;object_data[5]=0x00;object_data[6]=0x00;object_data[7]=0x00;
364 can_receive_flag = 0;
365 CAN_sendTxMessage(0x601,8,object_data);
366 HAL_Delay(1);
367while(1 != can_receive_flag)
368 {;}
369if(1 != RxData[4])
370 printf("Set PPM mode failed
");
371// 4. enable motor, write 0x0F to object 0x6040
372 printf("flag4 %d
",can_receive_flag);
373 object_data[0]=0x2B;object_data[1]=0x40;object_data[2]=0x60;object_data[3]=0x00;
374 object_data[4]=0x0F;object_data[5]=0x00;object_data[6]=0x00;object_data[7]=0x00;
375 can_receive_flag = 0;
376 CAN_sendTxMessage(0x601,8,object_data);
377 HAL_Delay(1);
378while(1 != can_receive_flag)
379 {;}
380// 5. check motor is enabled, read 0x6041
381 object_data[0]=0x40;object_data[1]=0x41;object_data[2]=0x60;object_data[3]=0x00;
382 object_data[4]=0x00;object_data[5]=0x00;object_data[6]=0x00;object_data[7]=0x00;
383 can_receive_flag = 0;
384 CAN_sendTxMessage(0x601,8,object_data);
385 HAL_Delay(10);
386while(1 != can_receive_flag)
387 {;}
388if((RxData[4] & 0x04)) //0x04 means drive is operation enabled
389 printf("PPM mode enable failed
");
390// 6. set profile velocity, write 10000 to 0x6081
391
392 object_data[0]=0x23;object_data[1]=0x81;object_data[2]=0x60;object_data[3]=0x00;
393 object_data[4]=0x10;object_data[5]=0x27;object_data[6]=0x00;object_data[7]=0x00;
394 can_receive_flag = 0;
395 CAN_sendTxMessage(0x601,8,object_data);
396 HAL_Delay(1);
397while(1 != can_receive_flag)
398 {;}
399// 7. read current position, read 0x6064
400 object_data[0]=0x40;object_data[1]=0x64;object_data[2]=0x60;object_data[3]=0x00;
401 object_data[4]=0x00;object_data[5]=0x00;object_data[6]=0x00;object_data[7]=0x00;
402 can_receive_flag = 0;
403 CAN_sendTxMessage(0x601,8,object_data);
404 HAL_Delay(1);
405while(1 != can_receive_flag)
406 {;}
407for(int i=0;i<4;i++)
408 can_Frame_DataField[i]=RxData[i+4];
409 int32_t current_Pos;
410 current_Pos = ConvertByteToInt(can_Frame_DataField);
411 printf("current pos is %d
",current_Pos);
412// 8. add 50000 counts on current position as target position, write 0x607A
413 int32_t target_Pos;
414 target_Pos = current_Pos + 5000;
415 printf("current pos is %d
",current_Pos);
416 ConvertIntTo4Byte(target_Pos);
417 object_data[0]=0x23; object_data[1]=0x7A; object_data[2]=0x60; object_data[3]=0x00;
418 object_data[4]=byte_value[0];object_data[5]=byte_value[1];object_data[6]=byte_value[2];object_data[7]=byte_value[3];
419 can_receive_flag = 0;
420 CAN_sendTxMessage(0x601,8,object_data);
421 HAL_Delay(1);
422while(1 != can_receive_flag)
423 {;}
424// 9. start motion, write 0x1F to object 0x6040
425 object_data[0]=0x2B;object_data[1]=0x40;object_data[2]=0x60;object_data[3]=0x00;
426 object_data[4]=0x1F;object_data[5]=0x00;object_data[6]=0x00;object_data[7]=0x00;
427 can_receive_flag = 0;
428 CAN_sendTxMessage(0x601,8,object_data);
429 HAL_Delay(1);
430while(1 != can_receive_flag)
431 {;}
432// 10. motion end
433 printf("PPM motion finished!
");
434
435}
436//TIM6 interrupt
437void HAL_TIM_PeriodElapsedCallback ( TIM_HandleTypeDef * htim )
438{
439if(htim == (&htim6))
440 {
441if(1 == CSP_flag)
442 {
443//send PDO
444 TxHeader.DLC = 4;
445 TxHeader.RTR = CAN_RTR_DATA;
446 ConvertIntTo4Byte(CSP_Pos[CSP_num]);
447 CAN_sendTxMessage(0x201,4,byte_value);
448
449//send SYNC
450 TxHeader.DLC = 0;
451 TxHeader.RTR = CAN_RTR_REMOTE;
452 CAN_sendTxMessage(0x80,0,byte_value);
453 CSP_num++;
454if(CSP_num > 60)
455 CSP_flag = 0;
456 }
457 }
458}
459
460//uartEX Receive to IDLE test
461void HAL_UARTEx_RxEventCallback ( UART_HandleTypeDef * huart, uint16_t Size)
462{
463 printf("%d
",Size);
464 HAL_UART_Transmit_DMA(&huart1,uart_rx_data,Size);
465
466 HAL_UARTEx_ReceiveToIdle_DMA(&huart1,uart_rx_data,uart_rx_max);
467 __HAL_DMA_DISABLE_IT(&hdma_usart1_rx, DMA_IT_HT);
468}
469
470
471//CAN RX interrupt
472void HAL_CAN_RxFifo0MsgPendingCallback ( CAN_HandleTypeDef * hcan )
473{
474 HAL_CAN_GetRxMessage(&hcan1,CAN_RX_FIFO0,&RxHeader,RxData);
475 can_receive_flag = 1;
476}
477//CAN send message
478void CAN_sendTxMessage(uint32_t std_id,uint32_t length,uint8_t data[])
479{
480 TxHeader.StdId = std_id;
481 TxHeader.DLC = length;
482 TxHeader.IDE = CAN_ID_STD;
483 TxHeader.RTR = CAN_RTR_DATA;
484 TxHeader.TransmitGlobalTime = DISABLE;
485
486if(HAL_CAN_AddTxMessage(&hcan1,&TxHeader,data,(uint32_t *)CAN_TX_MAILBOX0) != HAL_OK)
487 {
488 printf("CAN1 error");
489 }
490
491}
492
493// Mapping 0x607A to RPDO1 COB-ID 0x201
494void RPDO1_Mapping()
495{
496
497//step 1. 0x601 0x23 0x00 0x14 0x01 0x01 0x02 0x00 0x80
498 object_data[0]=0x23;object_data[1]=0x00;object_data[2]=0x14;object_data[3]=0x01;
499 object_data[4]=0x01;object_data[5]=0x02;object_data[6]=0x00;object_data[7]=0x80;
500 CAN_sendTxMessage(0x601,8,object_data);
501 HAL_Delay(10);
502// 2. 0x601 0x2F 0x00 0x14 0x02 0xFF
503 object_data[0]=0x2F;object_data[1]=0x00;object_data[2]=0x14;object_data[3]=0x02;
504 object_data[4]=0xFF;object_data[5]=0x00;object_data[6]=0x00;object_data[7]=0x80;
505 CAN_sendTxMessage(0x601,8,object_data);
506 HAL_Delay(10);
507// 3. 0x601 0x2F 0x00 0x16 0x00 0x00
508 object_data[0]=0x2F;object_data[1]=0x00;object_data[2]=0x16;object_data[3]=0x00;
509 object_data[4]=0x00;object_data[5]=0x00;object_data[6]=0x00;object_data[7]=0x00;
510 CAN_sendTxMessage(0x601,8,object_data);
511 HAL_Delay(10);
512// 4.0x601 0x23 0x00 0x16 0x01 0x20 0x00 0x7A 0x60
513 object_data[0]=0x23;object_data[1]=0x00;object_data[2]=0x16;object_data[3]=0x01;
514 object_data[4]=0x20;object_data[5]=0x00;object_data[6]=0x7A;object_data[7]=0x60;
515 CAN_sendTxMessage(0x601,8,object_data);
516 HAL_Delay(10);
517// 5. 0x601 0x2F 0x00 0x16 0x00 0x01
518 object_data[0]=0x2F;object_data[1]=0x00;object_data[2]=0x16;object_data[3]=0x00;
519 object_data[4]=0x01;object_data[5]=0x00;object_data[6]=0x00;object_data[7]=0x00;
520 CAN_sendTxMessage(0x601,8,object_data);
521 HAL_Delay(10);
522// 6. 0x601 0x23 0x00 0x14 0x01 0x01 0x02 0x00 0x00
523 object_data[0]=0x23;object_data[1]=0x00;object_data[2]=0x14;object_data[3]=0x01;
524 object_data[4]=0x01;object_data[5]=0x02;object_data[6]=0x00;object_data[7]=0x00;
525 CAN_sendTxMessage(0x601,8,object_data);
526 HAL_Delay(10);
527}
528
529//re-define printf
530int fputc(int ch,FILE *f)
531{
532 uint8_t temp[1] = {ch};
533 HAL_UART_Transmit(&huart1,temp,1,20);
534return ch;
535
536}
537
538//convert a 32bit data to 4 bytes
539void ConvertIntTo4Byte(int32_t source)
540{
541 byte_value[0] = 0xFF & source;
542 byte_value[1] = 0xFF &(source >> 8);
543 byte_value[2] = 0xFF &(source >> 16);
544 byte_value[3] = 0xFF &(source >> 24);
545}
546//convert 4 byte data to int32_t
547 int32_t ConvertByteToInt(uint8_t *byte_source)
548{
549 int32_t int32_data = 0;
550 int32_data = (int32_data | byte_source[3])<<8;
551 int32_data = (int32_data | byte_source[2])<<8;
552 int32_data = (int32_data | byte_source[1])<<8;
553 int32_data = (int32_data | byte_source[0]);
554
555return int32_data;
556}
557/* USER CODE END 4 */
558
559/**
560 * @brief This function is executed in case of error occurrence.
561 * @retval None
562*/
563void Error_Handler(void)
564{
565/* USER CODE BEGIN Error_Handler_Debug */
566/* User can add his own implementation to report the HAL error return state */
567 __disable_irq();
568while (1)
569 {
570//printf("%s %S",__FILE__,__DATE__);
571 }
572/* USER CODE END Error_Handler_Debug */
573}
574
575#ifdef USE_FULL_ASSERT
576/**
577 * @brief Reports the name of the source file and the source line number
578 * where the assert_param error has occurred.
579 * @param file: pointer to the source file name
580 * @param line: assert_param error line source number
581 * @retval None
582*/
583void assert_failed(uint8_t *file, uint32_t line)
584{
585/* USER CODE BEGIN 6 */
586/* User can add his own implementation to report the file name and line number,
587 ex: printf("Wrong parameters value: file %s on line %d
", file, line) */
588/* USER CODE END 6 */
589}
590#endif /* USE_FULL_ASSERT */
以上是 STM32F407CANopenmaster 的全部内容, 来源链接: utcz.com/z/520410.html