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 -----------------------------------------------*/
87 void SystemClock_Config(void);
88 /* USER CODE BEGIN PFP */
89 void CAN_sendTxMessage(uint32_t std_id,uint32_t length,uint8_t data[]);
90 void ConvertIntTo4Byte(int32_t source);
91 int32_t ConvertByteToInt(uint8_t *byte_source);
92 void do_a_PPM_Motion();
93 void do_a_CSP_Motion();
94 void 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 */
107 int 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!\n");
149 printf("After power up!Send 1 to activate PPM mode or send 2 to CSP mode\n");
150 RPDO1_Mapping();
151 HAL_Delay(10);
152
153 /* USER CODE END 2 */
154
155 /* Infinite loop */
156 /* USER CODE BEGIN WHILE */
157 while (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
165 if(1 == uart_rx_data[0])
166 { printf("PPM TEST\n");
167 do_a_PPM_Motion();
168 uart_rx_data[0] = 0;
169 }
170 else if(2 == uart_rx_data[0])
171 { printf("CSP TEST\n");
172 //initiate CSP mode pos array
173 for(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
178 if(i<=30)
179 CSP_Pos[i] = 0.5*acc*i*i; // S= 1/2*a*t*t a=100,
180 else
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 */
195 void 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;
216 if (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
230 if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_5) != HAL_OK)
231 {
232 Error_Handler();
233 }
234 }
235
236 /* USER CODE BEGIN 4 */
237 void 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
257 while(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);
265 while(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);
273 while(1 != can_receive_flag)
274 {;}
275 if(8 != RxData[4]) //8 means CSP mode
276 printf("Set CSP mode failed\n");
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);
283 while(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);
291 while(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);
299 while(1 != can_receive_flag)
300 {;}
301 if((RxData[4] & 0x04)) //0x04 means drive is operation enabled
302 printf("CSP mode enable failed\n");
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);
309 while(1 != can_receive_flag)
310 {;}
311 for(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\n",current_Pos);
316 // 8. CPS_Pos[]+current position as final target position
317 for(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
330 void 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\n",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
349 while(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\n",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);
358 while(1 != can_receive_flag)
359 {;}
360 // 3. check mode is PPM, read 0x6061
361 printf("flag3 %d\n",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);
367 while(1 != can_receive_flag)
368 {;}
369 if(1 != RxData[4])
370 printf("Set PPM mode failed\n");
371 // 4. enable motor, write 0x0F to object 0x6040
372 printf("flag4 %d\n",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);
378 while(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);
386 while(1 != can_receive_flag)
387 {;}
388 if((RxData[4] & 0x04)) //0x04 means drive is operation enabled
389 printf("PPM mode enable failed\n");
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);
397 while(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);
405 while(1 != can_receive_flag)
406 {;}
407 for(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\n",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\n",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);
422 while(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);
430 while(1 != can_receive_flag)
431 {;}
432 // 10. motion end
433 printf("PPM motion finished!\n");
434
435 }
436 //TIM6 interrupt
437 void HAL_TIM_PeriodElapsedCallback ( TIM_HandleTypeDef * htim )
438 {
439 if(htim == (&htim6))
440 {
441 if(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++;
454 if(CSP_num > 60)
455 CSP_flag = 0;
456 }
457 }
458 }
459
460 //uartEX Receive to IDLE test
461 void HAL_UARTEx_RxEventCallback ( UART_HandleTypeDef * huart, uint16_t Size)
462 {
463 printf("%d \n",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
472 void 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
478 void 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
486 if(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
494 void 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
530 int fputc(int ch,FILE *f)
531 {
532 uint8_t temp[1] = {ch};
533 HAL_UART_Transmit(&huart1,temp,1,20);
534 return ch;
535
536 }
537
538 //convert a 32bit data to 4 bytes
539 void 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
555 return 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 */
563 void 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();
568 while (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 */
583 void 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\r\n", file, line) */
588 /* USER CODE END 6 */
589 }
590 #endif /* USE_FULL_ASSERT */
文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,
LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L
目录一、ESP32简单介绍二、ESP32Wi-Fi模块介绍三、ESP32Wi-Fi编程模型四、ESP32Wi-Fi事件处理流程 五、ESP32Wi-Fi开发环境六、ESP32Wi-Fi具体代码七、ESP32Wi-Fi代码解读6.1主程序app_main7.2自定义代码wifi_init_sta()八、ESP32Wi-Fi连接验证8.1测试方法8.2服务器模拟工具sscom58.3测试代码8.4测试结果前言为了开发一款亚马逊物联网产品,开始入手ESP32模块。为了能够记录自己的学习过程,特记录如下操作过程。一、ESP32简单介绍ESP32是一套Wi-Fi(2.4GHz)和蓝牙(4.2)双模解决方
有道无术,术尚可求,有术无道,止于术。本系列SpringBoot版本3.0.4本系列SpringSecurity版本6.0.2本系列SpringAuthorizationServer版本1.0.2源码地址:https://gitee.com/pearl-organization/study-spring-security-demo文章目录前言1.OAuth2AuthorizationServerMetadataEndpointFilter2.OAuth2AuthorizationEndpointFilter3.OidcProviderConfigurationEndpointFilter4.N
在我的代码中,我需要使用各种算法(包括CRC32)对文件进行哈希处理。因为我还在Digest系列中使用其他加密哈希函数,所以我认为为它们维护一个一致的接口(interface)会很好。为了记录,我确实找到了digest-crc,一颗完全符合我要求的gem。问题是,Zlib是标准库的一部分,并且有一个我想重用的CRC32工作实现。此外,它是用C编写的,因此它应该提供与digest-crc相关的卓越性能,后者是纯ruby实现。实现Digest::CRC32一开始看起来非常简单:%w(digestzlib).each{|f|requiref}classDigest::CRC32一切正常:
我正在尝试在我的机器上安装win32-apigem,但在构建native扩展时我遇到了一些问题:$geminstallwin32-api--no-ri--rdocTemporarilyenhancingPATHtoincludeDevKit...Buildingnativeextensions.Thiscouldtakeawhile...C:\Programs\dev_kit\bin\make.exe:***Couldn'treservespaceforcygwin'sheap,Win32error0ERROR:Errorinstallingwin32-api:ERROR:Failed
我在Windows上运行ruby1.9.2并试图移植在Ruby1.8中工作的代码。该代码使用以前运行良好的Open4.popen4。对于1.9.2,我做了以下事情:通过geminstallPOpen4安装了POpen4需要POpen4通过require'popen4'尝试像这样使用POpen4:Open4.popen4("cmd"){|io_in,io_out,io_er|...}当我这样做时,我得到了错误:nosuchfiletoload--win32/open3如果我尝试安装win32-open3(geminstallwin32-open3),我会收到错误消息:win32-op
DellInspiron5488加内存32G 原装内置内存仅仅8G,目前看,真的太小了! 1.内存型号Dell5488内存型号:DDR42666。笔记本有两个内存插槽,原装占了一个,还能扩展一个。 2.买内存如果买Dell原装笔记本内存,8G就得500块左右。 我咨询了一下,三星的笔记本内存,可以兼容。16G,299块(2023年2月23日,京东价) Dell5488内存组合,最多只能插两根16G内存。 我于是买了两根三星16G内存。装上,很爽😄 跑国产系统统信UOS,再也看不到用交换区了,32G内存,爽!
本文代码使用HAL库。文章目录前言一、MCP4017的重要特性二、MCP4017计算RBW阻值三、MCP4017地址四、MCP4017读写函数五、CubeMX创建工程(利用ADC测量MCP4017电压)、对应代码:总结前言一、MCP4017的重要特性蓝桥杯板子上的是MCP4017T-104ELT,如图1。MCP4017是一个可编程电阻,通过写入的数值可以改变电阻的大小。重点在于6引脚(W),5引脚(B
STM32OTA应用开发——通过USB实现OTA升级目录STM32OTA应用开发——通过USB实现OTA升级前言1环境搭建2功能描述3BootLoader的制作4APP的制作5烧录下载配置6运行测试结束语前言什么是OTA?百度百科:空中下载技术(Over-the-AirTechnology;OTA),是通过移动通信的空中接口实现对移动终端设备及SIM卡数据进行远程管理的技术。经过公网多年的应用与发展,已十分成熟,网络运营商通过OTA技术实现SIM卡远程管理,还能提供移动化的新业务下载功能。实际上,现在我们所说的OTA比百度百科的定义还要更广泛,OTA的形式已经不再局限于手机和SIM卡,只要涉及