首先要安装cubemx跟Keil5两个编程软件,然后打开cubemx软件,新建一个工程项目:

a809c4af1ab064920f2acda60f95d4db.png

    输入CPU型号:

2f96b176be22051e7c5afeac9fce78a1.png

    在右下角双击CPU具体型号:

cf563a8ecd23b1087074d9cffdc5411f.png

    稍等片刻会打开如下对话框:

bd5c712b07db31427408258b951dfb47.png

    首先要配置系统的调试方式:我们选择SW方式,

73db87c6c6f2aa4d4e75210b0910e935.png

    然后配置晶振源,这里选择的是外部晶振,8M,

8e2f7f628f1c014386cc73fb024bbb0d.png

    使能看门狗,

3f29c559968948e18a0b2803dce9b347.png

    使能CAN,

957b2ed2bd9e25ae329971529d992bd8.png

    使能TIM2时钟源,采用内部时钟,

a9554469a33f8efba3d0786f49e0cb59.png

    配置完成后可以看到单片机管脚已经做了配置。

1d0efcfe346931ff129c5c4243831bef.png

    切换到Clock Configuration选项卡,配置时钟周期,这里配置为8M

84f8e1deaaa085be46dda2dc042f9a9e.png

    切换到Configuration选项卡,进入CAN配置选项配置波特率如下为500Kbps。

eca975614087b28daf4de5b0196cee3b.png

    配置接收中断。

b460cec4f52eaf0f535f20946a8433de.png

    配置定时器如下为1ms定时器。

020f69727d2a93fc100e91031cac6c5b.png

    配置定时器中断

0593a0236852b0ddedd6cb61c3e93602.png

    配置完成后点击保存,然后点击如下按钮,生成代码

af281227de962af66eec2ec3755e204b.png

    填写工程名称,路径,编程软件等等

05ff578cd23fb48bab7ea09f74223150.png

    选择生成代码的方式

7e8011174bdb54825726d54b6efcd9f7.png

    等待……

    之后点击打开项目。代码生成部分完成。

cb8b55d6791a8a3d3307adcc9b72f001.png

    添加一些特殊配置和逻辑代码,添加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 */
点击阅读全文
Logo

腾讯云面向开发者汇聚海量精品云计算使用和开发经验,营造开放的云计算技术生态圈。

更多推荐