zoukankan      html  css  js  c++  java
  • STM32F103C8T6 CAN通信详解

    之前在stm32f107上面整过can,这次换了一个芯片,是STM32F103C8T6,48引脚封装的,把之前的107的程序移植过来的时候

    不好使,无奈得重新配置,这次清楚的stm32的时钟和can的波特率学习了一遍,

    先介绍板子硬件资源:

    HSE时钟:8MHz;

    MCU : STM32F103C8T6

    CAN:一路;(注意:没有端口映射,使用PA11(can接收),PA12(can发送));

    一、时钟配置

    首先看看系统初始化时的时钟配置(使用的HSE时钟,只讲解从HSE时钟源到CAN时钟线路上的配置)

    先看初始化代码中部分:

     1 ; Reset handler
     2 Reset_Handler    PROC
     3                  EXPORT  Reset_Handler             [WEAK]
     4      IMPORT  __main
     5      IMPORT  SystemInit
     6                  LDR     R0, =SystemInit
     7                  BLX     R0
     8                  LDR     R0, =__main
     9                  BX      R0
    10                  ENDP
    View Code

    清楚的看到,在进入main函数之前,系统显示进入 SystemInit() 函数,进到这里看看;

     1 void SystemInit (void)
     2 {
     3   /* Reset the RCC clock configuration to the default reset state(for debug purpose) */
     4   /* Set HSION bit */
     5   RCC->CR |= (uint32_t)0x00000001;
     6 
     7   /* Reset SW, HPRE, PPRE1, PPRE2, ADCPRE and MCO bits */
     8 #ifndef STM32F10X_CL
     9   RCC->CFGR &= (uint32_t)0xF8FF0000;
    10 #else
    11   RCC->CFGR &= (uint32_t)0xF0FF0000;
    12 #endif /* STM32F10X_CL */   
    13   
    14   /* Reset HSEON, CSSON and PLLON bits */
    15   RCC->CR &= (uint32_t)0xFEF6FFFF;
    16 
    17   /* Reset HSEBYP bit */
    18   RCC->CR &= (uint32_t)0xFFFBFFFF;
    19 
    20   /* Reset PLLSRC, PLLXTPRE, PLLMUL and USBPRE/OTGFSPRE bits */
    21   RCC->CFGR &= (uint32_t)0xFF80FFFF;
    22 
    23 #ifdef STM32F10X_CL
    24   /* Reset PLL2ON and PLL3ON bits */
    25   RCC->CR &= (uint32_t)0xEBFFFFFF;
    26 
    27   /* Disable all interrupts and clear pending bits  */
    28   RCC->CIR = 0x00FF0000;
    29 
    30   /* Reset CFGR2 register */
    31   RCC->CFGR2 = 0x00000000;
    32 #elif defined (STM32F10X_LD_VL) || defined (STM32F10X_MD_VL) || (defined STM32F10X_HD_VL)
    33   /* Disable all interrupts and clear pending bits  */
    34   RCC->CIR = 0x009F0000;
    35 
    36   /* Reset CFGR2 register */
    37   RCC->CFGR2 = 0x00000000;      
    38 #else
    39   /* Disable all interrupts and clear pending bits  */
    40   RCC->CIR = 0x009F0000;
    41 #endif /* STM32F10X_CL */
    42     
    43 #if defined (STM32F10X_HD) || (defined STM32F10X_XL) || (defined STM32F10X_HD_VL)
    44   #ifdef DATA_IN_ExtSRAM
    45     SystemInit_ExtMemCtl(); 
    46   #endif /* DATA_IN_ExtSRAM */
    47 #endif 
    48 
    49   /* Configure the System clock frequency, HCLK, PCLK2 and PCLK1 prescalers */
    50   /* Configure the Flash Latency cycles and enable prefetch buffer */
    51   SetSysClock();
    52 
    53 #ifdef VECT_TAB_SRAM
    54   SCB->VTOR = SRAM_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal SRAM. */
    55 #else
    56   SCB->VTOR = FLASH_BASE | VECT_TAB_OFFSET; /* Vector Table Relocation in Internal FLASH. */
    57 #endif 
    58 }
    View Code

    面前一系列的RCC寄存器的初始化,还有一些条件编译选项,那些都是无关紧要的,对寄存器的初始化,

    还有就是根据mcu的型号选择不同的编译; 到最后那里调用了 SetSysClock() 函数,

    我们在进入到这个函数里看看,代码:

     1 static void SetSysClock(void)
     2 {
     3 #ifdef SYSCLK_FREQ_HSE
     4   SetSysClockToHSE();
     5 #elif defined SYSCLK_FREQ_24MHz
     6   SetSysClockTo24();
     7 #elif defined SYSCLK_FREQ_36MHz
     8   SetSysClockTo36();
     9 #elif defined SYSCLK_FREQ_48MHz
    10   SetSysClockTo48();
    11 #elif defined SYSCLK_FREQ_56MHz
    12   SetSysClockTo56();  
    13 #elif defined SYSCLK_FREQ_72MHz
    14   SetSysClockTo72();
    15 #endif
    16  
    17  /* If none of the define above is enabled, the HSI is used as System clock
    18     source (default after reset) */ 
    19 }
    View Code

    又是一些条件编译,没事,因为之前之前宏定义的是 

    #define SYSCLK_FREQ_72MHz  72000000

    所以程序进入到 SetSysClockTo72 函数中,看看这个函数里面:

      1 /**
      2   * @brief  Sets System clock frequency to 72MHz and configure HCLK, PCLK2 
      3   *         and PCLK1 prescalers. 
      4   * @note   This function should be used only after reset.
      5   * @param  None
      6   * @retval None
      7   */
      8 static void SetSysClockTo72(void)
      9 {
     10   __IO uint32_t StartUpCounter = 0, HSEStatus = 0;
     11   
     12   /* SYSCLK, HCLK, PCLK2 and PCLK1 configuration ---------------------------*/    
     13   /* Enable HSE */    
     14   RCC->CR |= ((uint32_t)RCC_CR_HSEON);
     15  
     16   /* Wait till HSE is ready and if Time out is reached exit */
     17   do
     18   {
     19     HSEStatus = RCC->CR & RCC_CR_HSERDY;
     20     StartUpCounter++; //HSE_STARTUP_TIMEOUT重拾计数,系统便不适用PLL,而使用内部8MHz晶振
     21   } while((HSEStatus == 0) && (StartUpCounter != HSE_STARTUP_TIMEOUT));
     22 
     23   if ((RCC->CR & RCC_CR_HSERDY) != RESET)
     24   {
     25     HSEStatus = (uint32_t)0x01;
     26   }
     27   else
     28   {
     29     HSEStatus = (uint32_t)0x00;
     30   }  
     31 
     32   if (HSEStatus == (uint32_t)0x01)
     33   {
     34     /* Enable Prefetch Buffer */
     35     FLASH->ACR |= FLASH_ACR_PRFTBE;
     36 
     37     /* Flash 2 wait state */
     38     FLASH->ACR &= (uint32_t)((uint32_t)~FLASH_ACR_LATENCY);
     39     FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY_2;    
     40 
     41  
     42     /* HCLK = SYSCLK */
     43     RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
     44       
     45     /* PCLK2 = HCLK */
     46     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE2_DIV1;
     47     
     48     /* PCLK1 = HCLK */
     49     RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;               //APB1分频系数:2   craigtao 2014-4-4
     50 
     51 #ifdef STM32F10X_CL
     52     /* Configure PLLs ------------------------------------------------------*/
     53     /* PLL2 configuration: PLL2CLK = (HSE / 5) * 8 = 40 MHz */
     54     /* PREDIV1 configuration: PREDIV1CLK = PLL2 / 5 = 8 MHz */
     55         
     56     RCC->CFGR2 &= (uint32_t)~(RCC_CFGR2_PREDIV2 | RCC_CFGR2_PLL2MUL |
     57                               RCC_CFGR2_PREDIV1 | RCC_CFGR2_PREDIV1SRC);
     58     RCC->CFGR2 |= (uint32_t)(RCC_CFGR2_PREDIV2_DIV5 | RCC_CFGR2_PLL2MUL8 |
     59                              RCC_CFGR2_PREDIV1SRC_PLL2 | RCC_CFGR2_PREDIV1_DIV5);
     60   
     61     /* Enable PLL2 */
     62     RCC->CR |= RCC_CR_PLL2ON;
     63     /* Wait till PLL2 is ready */
     64     while((RCC->CR & RCC_CR_PLL2RDY) == 0)
     65     {
     66     }
     67     
     68    
     69     /* PLL configuration: PLLCLK = PREDIV1 * 9 = 72 MHz */ 
     70     RCC->CFGR &= (uint32_t)~(RCC_CFGR_PLLXTPRE | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL);
     71     RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLXTPRE_PREDIV1 | RCC_CFGR_PLLSRC_PREDIV1 | 
     72                             RCC_CFGR_PLLMULL9); 
     73 #else    
     74     /*  PLL configuration: PLLCLK = HSE * 9 = 72 MHz */
     75     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLXTPRE |
     76                                         RCC_CFGR_PLLMULL));
     77     RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);        //PLL倍频系数:9   craigtao 2014-4-4
     78 #endif /* STM32F10X_CL */
     79 
     80     /* Enable PLL */
     81     RCC->CR |= RCC_CR_PLLON;
     82 
     83     /* Wait till PLL is ready */
     84     while((RCC->CR & RCC_CR_PLLRDY) == 0)
     85     {
     86     }
     87     
     88     /* Select PLL as system clock source */
     89     RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
     90     RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    
     91 
     92     /* Wait till PLL is used as system clock source */
     93     while ((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)0x08)
     94     {
     95     }
     96   }
     97   else
     98   { /* If HSE fails to start-up, the application will have wrong clock 
     99          configuration. User can add here some code to deal with this error */
    100   }
    101     StartUpCounter = 0x11223344;
    102     HSEStatus = 0x22334455;
    103 }
    View Code

    又是一些条件编译,不用在乎,结合mcu手册,关键的两行代码:

    /* PCLK1 = HCLK */
    RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE1_DIV2;               //APB1分频系数:2   craigtao 2014-4-4
    
    RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSE | RCC_CFGR_PLLMULL9);        //PLL倍频系数:9   craigtao 2014-4-4

    程序注释写得很明白,can使用的时钟是AHB低速APB1上的时钟,这里配置分频系数是 2 ; 时钟源是PLL提供

    在往上一级时钟就是PLL时钟,PLL时钟倍频系数是 9 ;作为APB1的输入时钟源

    HSE也就是外部接入的 8MHz 的晶振,作为PLL的输入时钟源,

    总结一下时钟的流向:

            HSE (8 MHz) -------> PLL倍频 (9 倍 = 72 MHz) ---------> APB1分频 (1/2 倍 = 36MHz) ------> can工作时钟 = 36 MHz 

    二、can波特率配置

    上面已经讲了,can工作的时钟是 : 36 MHz,清楚了这个以后,结合mcu手册,进行can波特率的设置,就从代码的角度讲解,看can波特率设置代码段:

    CAN_InitStructure.CAN_SJW=CAN_SJW_1tq; 
    CAN_InitStructure.CAN_BS1=CAN_BS1_3tq; 
    CAN_InitStructure.CAN_BS2=CAN_BS2_2tq;
    CAN_InitStructure.CAN_Prescaler=60;

    专用词汇名称在这里就不多讲解了,现在给出个公式: 8 (晶振) x 9 (PLL倍频) / 2 (APB1分频) / 60 / (1 + 3 + 2) = 0.1 = 100 (K)

    得到can的通信波特率 100 K;

    就套用这个公司,关键是得到can的时钟源,也就是第一里讲的内容,

    (以上只是个人的理解,没有很详细的写出来,希望大家多多批评)       

                                                                                                         craigtao    2014年4月4日

  • 相关阅读:
    AdaBoost算法学习
    梯度下降与随机梯度下降
    Logistic Regression学习
    PCA算法
    VS2013常见错误排查
    K临近算法
    遗传算法小结
    SLIC超像素(superpixel)算法
    openslide api函数概要
    线程钩子
  • 原文地址:https://www.cnblogs.com/craigtao/p/3645148.html
Copyright © 2011-2022 走看看