首先要安装cubemx跟Keil5两个编程软件,然后打开cubemx软件,新建一个工程项目:
输入CPU型号:
在右下角双击CPU具体型号:
稍等片刻会打开如下对话框:
首先要配置系统的调试方式:我们选择SW方式,
然后配置晶振源,这里选择的是外部晶振,8M,
使能看门狗,
使能CAN,
使能TIM2时钟源,采用内部时钟,
配置完成后可以看到单片机管脚已经做了配置。
切换到Clock Configuration选项卡,配置时钟周期,这里配置为8M
切换到Configuration选项卡,进入CAN配置选项配置波特率如下为500Kbps。
配置接收中断。
配置定时器如下为1ms定时器。
配置定时器中断
配置完成后点击保存,然后点击如下按钮,生成代码
填写工程名称,路径,编程软件等等
选择生成代码的方式
等待……
之后点击打开项目。代码生成部分完成。
添加一些特殊配置和逻辑代码,添加CAN的配置信息函数。
void Can_Config(void){ hcan.pTxMsg = &TxMessage; hcan.pRxMsg = &RxMessage; /*##-1- Configure CAN1 Transmission Massage #####################################*/ hcan.pTxMsg->StdId = 0x123; hcan.pTxMsg->RTR = CAN_RTR_DATA; hcan.pTxMsg->IDE = CAN_ID_STD; hcan.pTxMsg->DLC = 8; /*##-2- Configure the CAN1 Filter ###########################################*/ sFilterConfig.FilterNumber = 0; sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; sFilterConfig.FilterScale = CAN_FILTERSCALE_16BIT; sFilterConfig.FilterIdHigh = 0; sFilterConfig.FilterIdLow = 0; sFilterConfig.FilterMaskIdHigh = 0; sFilterConfig.FilterMaskIdLow = 0; sFilterConfig.FilterFIFOAssignment = CAN_FIFO0; sFilterConfig.FilterActivation = ENABLE; sFilterConfig.BankNumber = 14; HAL_CAN_ConfigFilter(&hcan, &sFilterConfig);}
在Main函数中while(1)之前调用一下即可,添加定时器启动函数:
HAL_TIM_Base_Start_IT(&htim2);
CAN接收中断启动函数:
HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);/* USER CODE BEGIN 2 */ Can_Config(); //Can配置信息HAL_TIM_Base_Start_IT(&htim2); //定时器启动HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);//使能Can接收中断 /* USER CODE END 2 */
打开stm32f1xx_it.c文件,找到如下函数,添加接收中断启动函数:
HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);
注意:接收中断启动函数使能一次只进一次中断,所以中断退出前要再次使能。
void USB_LP_CAN1_RX0_IRQHandler(void){ /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 0 */ /* USER CODE END USB_LP_CAN1_RX0_IRQn 0 */ HAL_CAN_IRQHandler(&hcan); /* USER CODE BEGIN USB_LP_CAN1_RX0_IRQn 1 */ HAL_CAN_Receive_IT(&hcan, CAN_FIFO0);//ʹÄÜCAN½ÓÊÕ /* USER CODE END USB_LP_CAN1_RX0_IRQn 1 */}
添加CAN接收服务函数:
HAL_CAN_RxCpltCallback
说明:该函数在stm32f1xx_hal_can.c文件中已经有定义,它的定义方式如下:
__weak void HAL_CAN_TxCpltCallback(CAN_HandleTypeDef* hcan)
函数前面的__weak关键字意思是如果有同样的定义,先执行没有__weak关键字的函数,所以当我们定义了HAL_CAN_RxCpltCallback函数后,编译器会先编译我们定义的函数,而忽略系统定义的该函数。当我们没有定义该函数时,系统会编译带有__weak关键字的函数。
void HAL_CAN_RxCpltCallback(CAN_HandleTypeDef* hcan){ unsigned short int speed; switch(hcan->pRxMsg->StdId) {//根据ID处理数据 case 0x123:// /*在此添加数据处理逻辑*/ break; default: break; }}
添加CAN发送函数:
/* USER CODE BEGIN WHILE */ while (1) { HAL_IWDG_Refresh(&hiwdg); //喂狗函数 if(Can_Trans_Timer == 0) {//每100ms发送一次数据 Can_Trans_Timer = 100; hcan.pTxMsg->StdId = 0x123; hcan.pTxMsg->Data[0] = 'C'; hcan.pTxMsg->Data[1] = 'A'; hcan.pTxMsg->Data[2] = 'N'; hcan.pTxMsg->Data[3] = ' '; hcan.pTxMsg->Data[4] = 'T'; hcan.pTxMsg->Data[5] = 'E'; hcan.pTxMsg->Data[6] = 'S'; hcan.pTxMsg->Data[7] = 'T'; HAL_CAN_Transmit(&hcan, 200);//发送一帧数据 } } /* USER CODE END WHILE */
在定时器函数中添加定时器代码:
void TIM2_IRQHandler(void){ /* USER CODE BEGIN TIM2_IRQn 0 */ if(Can_Trans_Timer > 0) Can_Trans_Timer--; /* USER CODE END TIM2_IRQn 0 */ HAL_TIM_IRQHandler(&htim2); /* USER CODE BEGIN TIM2_IRQn 1 */ /* USER CODE END TIM2_IRQn 1 */}
说明:在往工程中添加代码时要注意,不要任意往里面添加代码,要在注释着USER CODE BEGIN的地方添加代码,这样在重新生成代码时才不至于将已经写好的代码覆盖掉,如下
/* USER CODE BEGIN Includes */