STM32F407 CANopen master
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 */