笔记:stm32f030 要点总结(时钟、中断、GPIO、定时器、串口、看门狗)


不支持位带操作
只有一条AHB-lite总线接口连到存储器、总线矩阵等
1条外设总线,APB速度高达48MHz
4个中断优先级
GPIO连载AHB总线,最高翻转速度为12MHz

一、时钟系统

M0芯片的时钟源有4个,

一个高速内部RC时钟源,频率为8M,精度1%

一个高速外部时钟源,频率为8到32MHz

一个低速外部时钟源,频率一般为32.768kHz,驱动RTC

一个低速内部时钟源,频率为40kHz,驱动IWDG

芯片上电的时候默认启用内部RC震荡,即8MHz的内部时钟源

倍频最高48MHz

启用HSI

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
/*
*********************************************************************************************************
*   函 数 名: HSI_setSysClk
*   功能说明: 设置HSI为系统时钟,
*   形    参:
*   返 回 值: 无
*********************************************************************************************************
*/
void HSI_setSysClk(void)
{
  __IO uint32_t StartUpCounter = 0, HSIStatus = 0;
   
    /* SYSCLK, HCLK, PCLK configuration ----------------------------------------*/
    /* Enable HSI*/ //使能内部时钟  
    RCC->CR |= ((uint32_t)RCC_CR_HSION);//使用内部8M时钟
  
    /* Wait till HSI is ready and if Time out is reached exit */ //等待内部时钟起振
    do
    {
        HSIStatus = RCC->CR & RCC_CR_HSIRDY;
        StartUpCounter++;  
    }while((HSIStatus== 0) && (StartUpCounter != HSI_STARTUP_TIMEOUT));
 
    if ((RCC->CR & RCC_CR_HSIRDY) != RESET)//使用内部8M时钟
    {
        HSIStatus = (uint32_t)0x01;
    }
    else
    {
        HSIStatus = (uint32_t)0x00;
    }  
  
    if (HSIStatus == (uint32_t)0x01)
    {
        /* Enable Prefetch Buffer and set Flash Latency */ //flash总线时钟使能
        FLASH->ACR |= FLASH_ACR_PRFTBE;
        FLASH->ACR |= (uint32_t)FLASH_ACR_LATENCY;
 
        /* HCLK = SYSCLK *///外设AHB总线时钟等于系统时钟
        RCC->CFGR |= (uint32_t)RCC_CFGR_HPRE_DIV1;
 
        /* PCLK = HCLK *///外设APB总线时钟等于系统时钟
        RCC->CFGR |= (uint32_t)RCC_CFGR_PPRE_DIV1;
 
        /* PLL configuration = HSI/2 * 12= 48 MHz */
        RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_PLLSRC | RCC_CFGR_PLLSRC | RCC_CFGR_PLLMULL));
        RCC->CFGR |= (uint32_t)(RCC_CFGR_PLLSRC_HSI_Div2 | RCC_CFGR_PLLMULL12); //RC时钟2分频后 进行12倍频
         
        /* Enable PLL *///使能锁相环倍频开关 
        RCC->CR |= RCC_CR_PLLON;
 
        /* Wait till PLL is ready *///等待锁相环就绪 
        while((RCC->CR & RCC_CR_PLLRDY) == 0)
        {
        }
 
        /* Select PLL as system clock source *///选择锁相环输出时钟作为系统时钟 
        RCC->CFGR &= (uint32_t)((uint32_t)~(RCC_CFGR_SW));
        RCC->CFGR |= (uint32_t)RCC_CFGR_SW_PLL;    
 
        /* Wait till PLL is used as system clock source *///等待锁相环输出时钟已经成为系统时钟 
        while((RCC->CFGR & (uint32_t)RCC_CFGR_SWS) != (uint32_t)RCC_CFGR_SWS_PLL)
        {
        }
    }
    else
    /* If HSE fails to start-up, the application will have wrong clock 
         configuration. User can add here some code to deal with this error */
    }  
}



二、NVIC
4个中断优先级
1
2
3
/* 开关全局中断的宏 */
#define ENABLE_INT()    __enable_irq()     /* 使能全局中断 */
#define DISABLE_INT()   __disable_irq()    /* 禁止全局中断 */
1
2
3
4
5
6
7
8
9
10
void NVIC_Configuration(void)
{
  NVIC_InitTypeDef NVIC_InitStructure;
 
  /* 外设中断 */
  NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;                  //IRQ通道:串口1
  NVIC_InitStructure.NVIC_IRQChannelPriority = 1;                    //优先级 :1级
  NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                    //使能IRQ通道
  NVIC_Init(&NVIC_InitStructure);
}


三、GPIO

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
#define PORT_LED                  GPIOC                    //端口
#define PIN_LED                   GPIO_Pin_13              //引脚
 
#define LED_ON                    (PORT_LED->BSRR = PIN_LED)
#define LED_OFF                   (PORT_LED->BRR  = PIN_LED)
#define LED_TOGGLE                (PORT_LED->ODR ^= PIN_LED)
 
/*
**********************************************************************
* @fun     :bsp_led_init  
* @brief   :板上LED初始化
* @param   :None
* @return  :None 
* @remark  :
**********************************************************************
*/
void bsp_led_init(void)
{
    GPIO_InitTypeDef GPIO_InitStructure;
    RCC_AHBPeriphClockCmd(RCC_AHBPeriph_GPIOC, ENABLE);
 
    GPIO_InitStructure.GPIO_Pin = PIN_LED;                             //LED引脚
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;                      //输出模式
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;                  //高速输出
    GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;                     //推完输出
    GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;                   //无上下拉(浮空)
    GPIO_Init(PORT_LED, &GPIO_InitStructure);
}

四、定时器

滴答定时器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
/*
**********************************************************************
* @fun     :SysTick_Init  
* @brief   :滴答定时器初始化,提供1ms时基
* @param   :None
* @return  :=0,初始化成功;=1,初始化失败 
* @remark  :None
**********************************************************************
*/
unsigned char SysTick_Init(void)
{
    unsigned char sysFlag = 1;
     
    /* SystemFrequency / 1000    1ms中断一次
     * SystemFrequency / 100000  10us中断一次
     * SystemFrequency / 1000000 1us中断一次
     */ 
     
    sysFlag = SysTick_Config(SystemCoreClock / 1000);
 
    return sysFlag;
}
 
/*
**********************************************************************
* @fun     :bsp_DelayUS  
* @brief   :us级延迟。 必须在systick定时器启动后才能调用此函数
* @param   :None
* @return  :n-延迟长度,单位1 us
* @remark  :None
**********************************************************************
*/
void bsp_DelayUS(uint32_t n)
{
    uint32_t ticks;
    uint32_t told;
    uint32_t tnow;
    uint32_t tcnt = 0;
    uint32_t reload;
        
    reload = SysTick->LOAD;                
    ticks = n * (SystemCoreClock / 1000000); /* 需要的节拍数 */  
     
    tcnt = 0;
    told = SysTick->VAL;             /* 刚进入时的计数器值 */
 
    while (1)
    {
        tnow = SysTick->VAL;    
        if (tnow != told)
        {    
            /* SYSTICK是一个递减的计数器 */    
            if (tnow < told)
            {
                tcnt += told - tnow;    
            }
            /* 重新装载递减 */
            else
            {
                tcnt += reload - tnow + told;    
            }        
            told = tnow;
 
            /* 时间超过/等于要延迟的时间,则退出 */
            if (tcnt >= ticks)
            {
                break;
            }
        }  
    }
 
/*
**********************************************************************
* @fun     :SysTick_Handler  
* @brief   :滴答定时器中断服务函数
* @param   :None
* @return  :=0,初始化成功;=1,初始化失败 
* @remark  :None
**********************************************************************
*/
void SysTick_Handler(void)
{
 
}

五、串口

重定向prinf函数

1、需要在Options for Target -> Code Generation 中勾选Use MicroLIB;

2、需要加入下面这个函数:

int fputc(int ch, FILE *f)

{

  USART_SendData(USART1,(uint8_t)ch);

  while (USART_GetFlagStatus(USART1,USART_FLAG_TC) != SET);

  return (ch);

}

3、需要加入如下一个头文件:

#include "stdio.h"

(在网上看到多数人加了两个头文件:

#include "stdio.h"

#include "stdarg.h"

但在实际中只需加入一个头文件即可

)。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#ifdef __GNUC__
    #define PUTCHAR_PROTOTYPE int __io_putchar(int ch)
#else
    #define PUTCHAR_PROTOTYPE int fputc(int ch, FILE *f)
#endif
  
/** 
  * @brief  Retargets the C library printf function to the USART. 
  * @param  None 
  * @retval None 
  */  
PUTCHAR_PROTOTYPE  
{  
  /* Place your implementation of fputc here */  
  /* e.g. write a character to the USART */  
  USART_SendData(USART1, (uint8_t) ch);  
   
  /* Loop until the end of transmission */  
  while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET)  
  {  
  }  
   
  return ch;  
}



六、看门狗

驱动独立看门狗的晶振为40KHz

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
/*
**********************************************************************
* @fun     :bsp_iwdg_init  
* @brief   :独立看门狗初始化,超时时间2048ms
* @param   :None
* @return  :None 
* @remark  :
**********************************************************************
*/
void bsp_iwdg_init(void)
{
    if(RCC_GetFlagStatus(RCC_FLAG_IWDGRST) != RESET)
        RCC_ClearFlag();                             //清除标志
     
    IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);   //使能寄存器 写功能
    IWDG_SetPrescaler(IWDG_Prescaler_64);           //设置预分频 40K/64=0.625k 一个周期是 1.6ms
    IWDG_SetReload(1280);                          //1280*1.6ms=2048ms //设置初值
    IWDG_ReloadCounter();                           //喂狗
    IWDG_Enable();                                  //使能独立看门狗
}
 
/*
**********************************************************************
* @fun     :bsp_iwdg_feed  
* @brief   :独立看门狗喂狗,必须在超时时间内调用
* @param   :None
* @return  :None 
* @remark  :
**********************************************************************
*/
void bsp_iwdg_feed(void)
{
    IWDG_ReloadCounter();
}













原文地址:https://www.cnblogs.com/bog-box/p/11782230.html