STM32 命名规则

1


GPIO

头文件:stm32f10x_gpio.h

源文件:stm32f10x_gpio.c

重要函数:

  • 初始化函数:
    void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);

    初始化一个或者多个IO口(同一组)的工作方式和速度。

1
2
3
4
5
6
7
8
typedef struct
{
uint16_t GPIO_Pin; //指定要初始化的IO口
GPIOSpeed_TypeDef GPIO_Speed; //设置IO口输出速度
GPIOMode_TypeDef GPIO_Mode; //设置工作模式:8种中的一个
}GPIO_InitTypeDef;

GPIOx: GPIOA~GPIOG

​ GPIO_Init函数初始化样例:

1
2
3
4
5
6
GPIO_InitTypeDef  GPIO_InitStructure;

GPIO_InitStructure.GPIO_Pin = GPIO_Pin_5; //LED0-->PB.5 端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB.5
  • 2个读取输入电平函数:

    • uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
      作用:读取某个GPIO的输入电平。实际操作的是GPIOx_IDR寄存器。

      例:

      1
      GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_5);//读取GPIOA.5的输入电平
    • uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
      作用:读取某组GPIO的输入电平。实际操作的是GPIOx_IDR寄存器。
      例:

      1
      GPIO_ReadInputData(GPIOA);//读取GPIOA组中所有io口输入电平
  • 2个读取输出电平函数:

    • uint8_t GPIO_ReadOutputDataBit (GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
      作用:读取某个GPIO的输出电平。实际操作的是GPIO_ODR寄存器。

      例如:

      1
      GPIO_ReadOutputDataBit(GPIOA, GPIO_Pin_5);//读取GPIOA.5的输出电平
    • uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
      作用:读取某组GPIO的输出电平。实际操作的是GPIO_ODR寄存器。
      例如:

      1
      GPIO_ReadOutputData(GPIOA);//读取GPIOA组中所有io口输出电平
  • 4个设置输出电平函数:

    • void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
      作用:设置某个IO口输出为高电平(1)。实际操作BSRR寄存器
    • void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
      作用:设置某个IO口输出为低电平(0)。实际操作的BRR寄存器。
    • void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
    • void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
      这两个函数不常用,也是用来设置IO口输出电平。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
//按键输入:
u8 KEY_Scan(u8 mode)
{
static u8 key_up=1;
if(mode==1) key_up=1;//支持连续按
if(key_up && KEY按下)
{
delay_ms(10);//延时,防抖
key_up=0;//标记这次key已经按下
if(KEY确实按下)
{
return KEY_VALUE;
}
}else if(KEY没有按下) key_up=1;
return 没有按下
}

RCC

头文件: stm32f10x_rcc.h

源文件:stm32f10x_rcc.c

  1. 时钟使能配置:

    RCC_LSEConfig()RCC_HSEConfig()RCC_HSICmd()RCC_LSICmd()RCC_PLLCmd() ……

  2. 时钟源相关配置:
    RCC_PLLConfig ()RCC_SYSCLKConfig()RCC_RTCCLKConfig()

  3. 分频系数选择配置:
    RCC_HCLKConfig()RCC_PCLK1Config()RCC_PCLK2Config()

  4. 外设时钟使能:
    RCC_APB1PeriphClockCmd(): //APB1线上外设时钟使能
    RCC_APB2PeriphClockCmd(); //APB2线上外设时钟使能
    RCC_AHBPeriphClockCmd(); //AHB线上外设时钟使能

  5. 其他外设时钟配置:

    RCC_ADCCLKConfig (); RCC_RTCCLKConfig();

  6. 状态参数获取参数:
    RCC_GetClocksFreq();
    RCC_GetSYSCLKSource();
    RCC_GetFlagStatus()

  7. RCC中断相关函数 :
    RCC_ITConfig()RCC_GetITStatus()RCC_ClearITPendingBit()


NVIC中断优先级分组

  • 中断管理方法:

    首先,对STM32中断进行分组,组0~4。同时,对每个中断设置一个抢占优先级和一个响应优先级值。

  • 抢占优先级 & 响应优先级区别:

    高优先级的抢占优先级是可以打断正在进行的低抢占优先级中断的。

    抢占优先级相同的中断,高响应优先级不可以打断低响应优先级的中断。

    抢占优先级相同的中断,当两个中断同时发生的情况下,哪个响应优先级高,哪个先执行。

    如果两个中断的抢占优先级和响应优先级都是一样的话,则看哪个中断先发生就先执行;

  • 一般情况下,系统代码执行过程中,只设置一次中断优先级分组,比如分组2,设置好分组之后一般不会再改变分组。随意改变分组会导致中断管理混乱,程序出现意想不到的执行结果。

  • 中断优先级分组函数:

    1
    2
    3
    4
    5
    6
    7
    8
    9
    void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);

    void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
    {
    assert_param(IS_NVIC_PRIORITY_GROUP(NVIC_PriorityGroup));
    SCB->AIRCR = AIRCR_VECTKEY_MASK | NVIC_PriorityGroup;
    }

    NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
  • 中断参数初始化函数:

    void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);

    1
    2
    3
    4
    5
    6
    7
    typedef struct
    {
    uint8_t NVIC_IRQChannel; //设置中断通道
    uint8_t NVIC_IRQChannelPreemptionPriority;//设置响应优先级
    uint8_t NVIC_IRQChannelSubPriority; //设置抢占优先级
    FunctionalState NVIC_IRQChannelCmd; //使能/使能
    } NVIC_InitTypeDef;

    例:

    1
    2
    3
    4
    5
    6
    7
    NVIC_InitTypeDef   NVIC_InitStructure;

    NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//串口1中断
    NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1 ;// 抢占优先级为1
    NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;// 子优先级位2
    NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能
    NVIC_Init(&NVIC_InitStructure); //根据上面指定的参数初始化NVIC寄存器
  • 中断优先级设置步骤:

    1. 系统运行后先设置中断优先级分组。调用函数:
      void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
      (整个系统执行过程中,只设置一次中断分组。)
    2. 针对每个中断,设置对应的抢占优先级和响应优先级:
      void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
    3. 如果需要挂起/解挂,查看中断当前激活状态,分别调用相关函数即可。

串口

1
2
3
4
5
6
7
8
9
10
11
void USART_Init(); //串口初始化:波特率,数据字长,奇偶校验,硬件流控以及收发使能
void USART_Cmd();//使能串口
void USART_ITConfig();//使能相关中断

void USART_SendData();//发送数据到串口,DR
uint16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据

FlagStatus USART_GetFlagStatus();//获取状态标志位
void USART_ClearFlag();//清除状态标志位
ITStatus USART_GetITStatus();//获取中断状态标志位
void USART_ClearITPendingBit();//清除中断状态标志位

波特率计算方法

2

3

串口配置的一般步骤

  1. 串口时钟使能,GPIO时钟使能:RCC_APB2PeriphClockCmd();
  2. 串口复位:USART_DeInit(); 这一步不是必须的
  3. GPIO端口模式设置:GPIO_Init(); 模式设置为GPIO_Mode_AF_PP
  4. 串口参数初始化:USART_Init();
  5. 开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤)
      NVIC_Init();
      USART_ITConfig();
    
  6. 使能串口:USART_Cmd();
  7. 编写中断处理函数:USARTx_IRQHandler();
  8. 串口数据收发:
    void USART_SendData();//发送数据到串口,DR
    uint16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据
  9. 串口传输状态获取:
    FlagStatus USART_GetFlagStatus(USART_TypeDef USARTx, uint16_t USART_FLAG);
    void USART_ClearITPendingBit(USART_TypeDef
    USARTx, uint16_t USART_IT);

外部中断

  • void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
    //设置IO口与中断线的映射关系

    例:

    1
    GPIO_EXTILineConfig(GPIO_PortSourceGPIOE,GPIO_PinSource2);
  • void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
    //初始化中断线:触发方式等

    1
    2
    3
    4
    5
    6
    7
    typedef struct
    {
    uint32_t EXTI_Line; //指定要配置的中断线
    EXTIMode_TypeDef EXTI_Mode; //模式:事件 OR中断
    EXTITrigger_TypeDef EXTI_Trigger;//触发方式:上升沿/下降沿/双沿触发
    FunctionalState EXTI_LineCmd; //使能 OR失能
    }EXTI_InitTypeDef;
    1
    2
    3
    4
    5
    EXTI_InitStructure.EXTI_Line=EXTI_Line2;	 
    EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt;
    EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling;
    EXTI_InitStructure.EXTI_LineCmd = ENABLE;
    EXTI_Init(&EXTI_InitStructure);
  • ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
    //判断中断线中断状态,是否发生

  • void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
    //清除中断线上的中断标志位

  • 外部中断的一般配置步骤:

    1. 初始化IO口为输入。
      GPIO_Init();
      
    2. 开启IO口复用时钟。
      RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
      
    3. 设置IO口与中断线的映射关系。
      void GPIO_EXTILineConfig();
      
    4. 初始化线上中断,设置触发条件等。
         EXTI_Init();
      
    5. 配置中断分组(NVIC),并使能中断。
         NVIC_Init();
      
    6. 编写中断服务函数。
        EXTIx_IRQHandler();
      
    7. 清除中断标志位
        EXTI_ClearITPendingBit();
      

通用定时器

  • 定时器参数初始化:

    void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);

    1
    2
    3
    4
    5
    6
    7
    8
    typedef struct
    {
    uint16_t TIM_Prescaler;
    uint16_t TIM_CounterMode;
    uint16_t TIM_Period;
    uint16_t TIM_ClockDivision;
    uint8_t TIM_RepetitionCounter;
    } TIM_TimeBaseInitTypeDef;
    1
    2
    TIM_TimeBaseStructure.TIM_Period = 4999; TIM_TimeBaseStructure.TIM_Prescaler =7199; TIM_TimeBaseStructure.TIM_ClockDivision =   TIM_CKD_DIV1; TIM_TimeBaseStructure.TIM_CounterMode =   TIM_CounterMode_Up; 
    TIM_TimeBaseInit(TIM3, &TIM_TimeBaseStructure);
  • 定时器使能函数:

    void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)

  • 定时器中断使能函数:

    void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);

  • 状态标志位获取和清除:

    FlagStatus TIM_GetFlagStatus(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
    void TIM_ClearFlag(TIM_TypeDef* TIMx, uint16_t TIM_FLAG);
    ITStatus TIM_GetITStatus(TIM_TypeDef* TIMx, uint16_t TIM_IT);
    void TIM_ClearITPendingBit(TIM_TypeDef* TIMx, uint16_t TIM_IT);

  • 定时器中断实现步骤

    1. 能定时器时钟。
        RCC_APB1PeriphClockCmd();
      
    2. 初始化定时器,配置ARR,PSC。
      TIM_TimeBaseInit();
      
    3. 开启定时器中断,配置NVIC。
      void TIM_ITConfig();
      NVIC_Init();
      
    4. 使能定时器。
      TIM_Cmd();
      
    5. 编写中断服务函数。
      TIMx_IRQHandler();
      

PWM输出

  • 初始化:

    void TIM_OCxInit(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    typedef struct
    {
    uint16_t TIM_OCMode; //PWM模式1或者模式2
    uint16_t TIM_OutputState; //输出使能 OR失能
    uint16_t TIM_OutputNState;
    uint16_t TIM_Pulse; //比较值,写CCRx
    uint16_t TIM_OCPolarity; //比较输出极性
    uint16_t TIM_OCNPolarity;
    uint16_t TIM_OCIdleState;
    uint16_t TIM_OCNIdleState;
    } TIM_OCInitTypeDef;
    1
    2
    3
    4
    5
    TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM2; //PWM模式2
    TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
    TIM_OCInitStructure. TIM_Pulse=100;
    TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_High; //输出极性:TIM输出比较极性高
    TIM_OC2Init(TIM3, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM3 OC2
  • 设置比较值函数:

    void TIM_SetCompareX(TIM_TypeDef* TIMx, uint16_t Compare2);

  • 使能输出比较预装载:

    void TIM_OC2PreloadConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPreload);

  • 使能自动重装载的预装载寄存器允许位:

    void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);

  • PWM输出配置步骤:

    1. 使能定时器3和相关IO口时钟。
      使能定时器3时钟:RCC_APB1PeriphClockCmd();
      使能GPIOB时钟:RCC_APB2PeriphClockCmd();
      
    2. 初始化IO口为复用功能输出。函数:GPIO_Init();
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;      
      
    3. 这里我们是要把PB5用作定时器的PWM输出引脚,所以要重映射配置,
      所以需要开启AFIO时钟。同时设置重映射。
       RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
       GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3, ENABLE); 
      
    4. 初始化定时器:ARR,PSC等:TIM_TimeBaseInit();
    5. 初始化输出比较参数:TIM_OC2Init()
    6. 使能预装载寄存器: TIM_OC2PreloadConfig(TIM3, TIM_OCPreload_Enable);
    7. 使能定时器。TIM_Cmd();
    8. 不断改变比较值CCRx,达到不同的占空比效果:TIM_SetCompare2();

输入捕获

  • 初始化函数:

    void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct);

    1
    2
    3
    4
    5
    6
    7
    8
    typedef struct
    {
    uint16_t TIM_Channel; //捕获通道1-4
    uint16_t TIM_ICPolarity; //捕获极性
    uint16_t TIM_ICSelection; //映射关系
    uint16_t TIM_ICPrescaler; //分频系数
    uint16_t TIM_ICFilter; //滤波器
    } TIM_ICInitTypeDef;
    1
    2
    3
    4
    5
    TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising;
    TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI;
    TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1;
    TIM5_ICInitStructure.TIM_ICFilter = 0x00;
    TIM_ICInit(TIM5, &TIM5_ICInitStructure);
  • 通道极性设置独立函数:

    void TIM_OCxPolarityConfig(TIM_TypeDef* TIMx, uint16_t TIM_OCPolarity);

  • 获取通道捕获值

    uint32_t TIM_GetCapture1(TIM_TypeDef* TIMx);

  • 输入捕获的一般配置步骤:

    1. 初始化定时器和通道对应IO的时钟。
    2. 初始化IO口,模式为输入:GPIO_Init();
      GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPD; //PA0 输入
      
    3. 初始化定时器ARR,PSC
      TIM_TimeBaseInit();
    4. 初始化输入捕获通道
      TIM_ICInit();
    5. 如果要开启捕获中断,
      TIM_ITConfig();
      NVIC_Init();
      
    6. 使能定时器:TIM_Cmd();
    7. 编写中断服务函数:TIMx_IRQHandler();

DMA

DMA,全称Direct Memory Access,即直接存储器访问。

DMA的出现就是为了解决批量数据的输入/输出问题。DMA是指外部设备不通过CPU而直接与系统内存交换数据的接口技术。这样数据的传送速度就取决于存储器和外设的工作速度。

  • 初始化函数:

    void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);

  • 2个使能函数:

    • void DMA_Cmd(DMA_Channel_TypeDef* DMAy_Channelx, FunctionalState NewState);//使能DMA通道
    • void DMA_ITConfig(DMA_Channel_TypeDef* DMAy_Channelx, uint32_t DMA_IT, FunctionalState NewState);//使能DMA通道中断
  • 2个传输数据量函数

    • void DMA_SetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx, uint16_t DataNumber);//设置DMA通道的传输数据量(DMA处于关闭状态)
    • uint16_t DMA_GetCurrDataCounter(DMA_Channel_TypeDef* DMAy_Channelx);//获取当前DMA通道传输剩余数据量(DMA处于开启状态)
  • DMA的一般步骤

    • 使能DMA时钟。调用函数:RCC_AHBPeriphClockCmd()
    • 初始化DMA通道参数。调用函数:DMA_Init()
    • 使能串口DMA发送,串口DMA使能函数。调用函数:USART_DMACmd()
    • 使能DMA1通道,启动传输。调用函数:DMA_Cmd()
    • 查询DMA传输状态。调用函数:DMA_GetFlagStatus()
    • 获取/设置通道当前剩余数据量。调用函数:DMA_GetCurrDataCounter()DMA_SetCurrDataCounter()