STM32技术详解
一、前言
STM32芯片组成
ARM内核+ST设计的外围电路
系统结构
工程架构
二、GPIO
1、GPIO简介
1、GPIO通用输入输出口
2、引脚电平:0~3.3V
3、输出模式:输出高低电平、驱动LED、蜂鸣器等
4、输入模式:读取端口电平、ADC电压采集、读取按键输入等
2、GPIO基本结构
GPIO挂载在APB2总线上
3、GPIO八种模式
4、GPIO程序步骤
1、使用RCC开启GPIO的时钟
作用:使能(开启)或失能(关闭)APB2外设时钟
RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
参数 | 说明 | 示例 |
RCC_APB2Periph | 指明需要开启的是哪一个APB2外设 |
RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE, RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG,
RCC_APB2Periph_ADC1, RCC_APB2Periph_ADC3,
RCC_APB2Periph_USART1,
RCC_APB2Periph_SPI1,
RCC_APB2Periph_TIM1, RCC_APB2Periph_TIM16, RCC_APB2Periph_TIM17, RCC_APB2Periph_TIM10, RCC_APB2Periph_TIM11 |
NewState | NewState:指定外设时钟的新状态 |
ENABLE(打开) DISABLE(关闭) |
2、使用GPIO_Init函数初始化GPIO
作用:根据GPIO_InitStruct中的指定参数初始化GPIOx外设
GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
参数 | 说明 | 示例 |
GPIOx | 其中x可以为(A…G)选择GPIO外设。 |
GPIOA, GPIOB, GPIOD, GPIOE, GPIOF, GPIOG, |
GPIO_InitStruct | 指向GPIO InitTypeDef结构的指针,该结构包含指定GPIO外设的配置信息。 |
typedef struct { |
参数说明:
3、使用输出或者输入的函数控制GPIO口
写引脚:
void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal); //可以对16个端口同时写入
读引脚:
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); //读取某一位
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx); //读取整个寄存器
翻转:
if(GPIO_ReadOutputDataBit(GPIOB, GPIO_Pin_5)==0) //读输出引脚
{
GPIO_SetBits(GPIOB, GPIO_Pin_5); //翻转
}
else
{
GPIO_ResetBits(GPIOB, GPIO_Pin_5);
}
三、外部中断EXIT
1、中断简介
主程序运行中,发生中断时,使CPU暂停当前正在运行的程序,转去处理中断程序,处理完后又返回原来被暂停的位置继续运行
有68个可屏蔽中断源,包括了EXIT、TIM、ADC、USART、SPI、I2C、RTC等多个外设
2、NVIC简介
NVIC:嵌套向量中断控制器。用来管理中断
NVIC基本结构:
NVIC优先级分组:
3、EXIT简介
外部中断,检测GPIO口的电平,当指定的GPIO发生变化,向NVIC发送中断信号,产生中断
触发方式:1、上升沿
2、下降沿
3、双边沿
4、软件触发
支持的GPIO口:所有GPIO口。但不同组的相同Pin不能同时触发。例如:PA0、PB0、PC0等
触发方式:中断响应(触发中断) / 事件响应(不触发中断,中断信号不传给CPU处理,而是触发其他外设)
4、EXIT基本结构
5、AFIO复用IO口
作用:复用引脚重映射、中断引脚选择
6、EXIT程序步骤
1、配置RCC,将程序涉及外设的时钟都打开(有GPIO和AFIO)
RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState)
2、使用GPIO_Init函数初始化GPIO
GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct)
3、配置AFIO
作用:选择硬件所用的那一路GPIO,连接到后面的EXTI作用。
void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource)
参数 | 说明 | 示例 |
GPIO_PortSource | 选择要用作EXTI线路源的GPIO端口 |
GPIO_PortSourceGPIOA, GPIO_PortSourceGPIOB, GPIO_PortSourceGPIOD, GPIO_PortSourceGPIOE, GPIO_PortSourceGPIOF, GPIO_PortSourceGPIOG, |
GPIO_PinSource | GPIO_PinSource:要配置的EXTI线路 |
GPIO_PinSource0 GPIO_PinSource1 …… GPIO_PinSource15 |
4、配置EXTI
作用:1、选择边沿触发方式,比如上升沿、下降沿或者双边沿,还有选择触发响应方式,可以选择中断响应和事件响应
2、根据EXTI InitStruct中的指定参数初始化EXTI外设
void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct)
参数说明:
参数 | 说明 | 示例 |
EXTI_InitStruct | 指向EXTI InitTypeDef结构体的指针包含EXTI外设的配置信息。 |
typedef struct { |
5、配置NVIC
1.1、配置优先级分组,抢占优先级和响应优先级
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup)
参数说明:
参数 | 说明 | 示例 |
NVIC_PriorityGroup | 指定优先级分组位长度。 |
NVIC_PriorityGroup_0(0位抢占,4位响应) NVIC_PriorityGroup_1(1位抢占,3位响应) NVIC_PriorityGroup_2(2位抢占,2位响应) NVIC_PriorityGroup_3(3位抢占,1位响应) NVIC_PriorityGroup_4(4位抢占,0位响应) |
1.2、初始化NVIC
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct)
参数说明:
6、实现中断函数
中断向量表:
根据中断向量表,找到所需中断函数,这里面以IRQHandler结尾的字符串就是中断函数的名字,再根据名字写中断函数。
void EXTI3_IRQHandler(void)
{
if(EXTI_GetITStatus(uint32_t EXTI_Line)==1) //判断中断标志位是否设置
{
/*
中断执行的任务
*/
}
EXTI_ClearITPendingBit(uint32_t EXTI_Line); //最后要清除中断标志位,结束中断
}
常用的EXIT函数:
EXTI_GetITStatus(uint32_t EXTI_Line); //检查指定的外部中断上的中断标志是否被设置。
EXTI_ClearITPendingBit(uint32_t EXTI_Line); //清除中断标志位,结束中断
四、TIM定时中断
1、TIM简介
STM32的定时器拥有16位计数器、预分频器、自动重装载寄存器的时基单元,在72MHZ计数时钟下可以实现最大59.65s的定时
不仅具备基本定时中断功能,还包括内外时钟源选择、输入捕获、输出比较、主从触发等模式
通用、基本、高级定时器基本频率都是72MHZ
2、定时器类型
3、定时器中断基本结构
4、时钟树
5、定时器中断程序步骤
1.1、定时器内部时钟
1、开启定时器的RCC时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE); //开启TIM2时钟
2、选择时基单元的时钟源为内部时钟源
对于定时中断,我们就选择内部时钟源
函数作用:定时器TIMx配置内部时钟
TIM_InternalClockConfig(TIM_TypeDef* TIMx)
参数 | 说明 | 示例 |
TIMx | 所选择的 TIM 外设 |
TIM1 … TIM8 |
3、配置时基单元
作用:设置预分频器、自动重装器、计数模式等等,这些参数用一个结构体就可以配置好了。
void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct)
参数说明:
参数 | 说明 | 示例 |
TIMx | 所选择的 TIM 外设 |
TIM1 … TIM8 |
TIM_TimeBaseInitStruct | 指向结构 TIM_TimeBaseInitTypeDef 的指针,包含了 TIMx 时间基数单位的配置信息 |
typedef struct TIM_CounterMode; TIM_Period; } TIM_TimeBaseInitTypeDef; |
4、配置输出中断控制
作用:允许更新中断输出到NVIC(开启更新中断到NVIC的通路)
void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState)
参数说明:
参数 | 说明 | 示例 |
TIMx | 所选择的 TIM 外设 |
TIM1 … TIM8 |
TIM_IT | TIM 中断类型 |
TIM_IT_Update(更新中断) TIM_IT_CC1(捕获/比较中断) TIM_IT_CC2(捕获/比较中断) TIM_IT_CC3(捕获/比较中断) TIM_IT_CC4(捕获/比较中断) |
NewState | TIMx 中断的新状态 |
ENABLE 或 DISABLE |
5、配置NVIC
作用:在NMC中打开定时器中断的通道,并分配一个优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);
NVIC_InitTypeDef NVIC_InitStruct;
NVIC_InitStruct.NVIC_IRQChannel=TIM2_IRQn;
NVIC_InitStruct.NVIC_IRQChannelCmd=ENABLE;
NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority=0;
NVIC_InitStruct.NVIC_IRQChannelSubPriority=0;
NVIC_Init(&NVIC_InitStruct);
6、启动定时器
作用:整个模块配置完成后,需要使能计数器。要不然计数器是不会运行的。当定时器使能后,计数器就会开始计数了,当计数器更新时,触发中断
void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState)
参数说明:
参数 | 说明 | 示例 |
TIMx | 所选择的 TIM 外设 |
TIM1 … TIM8 |
NewState | TIMx 中断的新状态 |
ENABLE 或 DISABLE |
7、实现定时中断函数
void TIM2_IRQHandler(void)
{
if(TIM_GetITStatus(TIM2,TIM_IT_Update)==1) //判断中断标志位是否设置
{
/*
中断执行的任务
*/
}
TIM_ClearITPendingBit(TIM2,TIM_IT_Update); //最后要清除中断标志位,结束中断
}
常用函数:
1.2、定时器外部时钟
1、开启GPIO的RCC时钟
将定时器的ETR引脚对应的GPIO设置为输入模式
2、时基单元的时钟源设置为外部模式2
void TIM_ETRClockMode2Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity, uint16_t ExtTRGFilter)
参数 | 说明 | 示例 |
TIMx | 所选择的 TIM 外设 |
TIM1 … TIM8 |
TIM_ExtTRGPrescaler | 外部触发预分频 |
TIM_ExtTRGPSC_OFF TIM_ExtTRGPSC_DIV2 TIM_ExtTRGPSC_DIV4 TIM_ExtTRGPSC_DIV8 |
TIM_ExtTRGPolarity | 设置外部触发信号的极性 |
TIM_ExtTRGPolarity_Inverted(低电平或下降沿) TIM_ExtTRGPolarity_NonInverted(高电平或上升沿) |
ExtTRGFilter | 设置外部触发信号的滤波器 | 0x00~0x0F |
五、TIM输出比较
1、输出比较简介
OC(输出比较)
通过比较CNT(计数器)与CCR寄存器(捕获/比较寄存器)的值,来对输出电平进行置1、0或翻转,用于输出一定频率和占空比的PWM波形
每个高级和通用定时器都拥有4个输出比较通道
2、输出比较通道
3、输出比较模式
4、PWM基本结构
5、参数计算
6、输出比较程序步骤
1、RCC开启时钟
把我们要用的TIM外设和GPIO外设的时钟打开
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM2, ENABLE);
2、配置时基单元
TIM_InternalClockConfig(TIM2);
TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct);
3、配置输出比较单元
作用:主要配置包括CCR的值、输出比较模式、极性选择、输出使能等参数
void TIM_OCXInit(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct) //通道X
参数说明:
参数 | 说明 | 示例 |
TIMx | 所选择的 TIM 外设 |
TIM1 … TIM8 |
TIM_OCInitStruct | 指向结构 TIM_OCInitTypeDef 的指针,包含了 TIMx 时间基数单位的配置信息 |
typedef struct TIM_OCPolarity; TIM_OutputState; }TIM_OCInitTypeDef |
注意:通用定时器一般只使用TIM_OCInitStruct结构体部分成员,另一些是高级定时器专属,但是必须初始化,然后在修改结构体成员,所以使用结构体初始化函数
void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct)
4、配置定时器某个通道所使用的GPIO引脚
作用:把PWM对应的GPIO口,初始化为复用推挽输出的配置
只有把GPIO设置成复用推挽输出,引脚的控制权才能交给片上外设,PWM波形才能通过引脚输出
5、启动定时器
TIM_Cmd(TIM2, ENABLE);
6、实现PWM
作用:更改CCR的值
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1) //通道1
参数 | 说明 |
TIMx | 所选择的TIM外设,对于通用定时器来说是2、3、4 |
Compare1 | 指定捕获比较程序寄存器的新值 |
7、引脚重映射
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO, ENABLE); //开启AFIO
GPIO_PinRemapConfig(GPIO_PartialRemap_TIM3,ENABLE); //引脚重映射
六、TIM输入捕获
1、输入捕获简介
输入捕获模式下,当通道输入引脚发生指定电平跳变,当前CNT的值将锁存到CCR中,可用于测量PWM波形的频率、占空比、电平持续时间等参数
配置为PWMI模式,同时测量频率和占空比
可配合主从触发模式,实现硬件全自动测量
2、输入捕获通道
3、主从触发模式
4、输入捕获基本结构
5、输入捕获程序步骤
1、RCC开启时钟,把GPIO和TIM的时钟打开
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM3, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
2、GPIO初始化,把GPIO设置成输入模式
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_6;
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
3、配置时基单元
作用:让CNT计数器在内部时钟的驱动下自增运行
TIM_InternalClockConfig(TIM3);
TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
TIM_TimeBaseInitStruct.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInitStruct.TIM_CounterMode=TIM_CounterMode_Up;
TIM_TimeBaseInitStruct.TIM_Period=65536-1;
TIM_TimeBaseInitStruct.TIM_Prescaler=7200-1;
TIM_TimeBaseInitStruct.TIM_RepetitionCounter=0;
TIM_TimeBaseInit(TIM3, &TIM_TimeBaseInitStruct);
4、配置输入捕获单元
作用:设置滤波器、极性、直连通道还是交叉通道、分频器等参数
void TIM_ICInit(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct); //配置一个通道
void TIM_PWMIConfig(TIM_TypeDef* TIMx, TIM_ICInitTypeDef* TIM_ICInitStruct); //配置两个通道
参数说明:
参数 | 说明 | 示例 |
TIMx | 所选择的 TIM 外设 |
TIM1 … TIM8 |
TIM_ICInitStruct | 指向结构 TIM_ICInitTypeDef 的指针,包含了 TIMx 输入捕获的配置信息 |
typedef struct TIM_ICFilter; TIM_ICPolarity; TIM_ICSelection; }TIM_ICInitTypeDef |
5、选择从模式的触发源
作用:配置TRGI的触发源为TI1FP1
void TIM_SelectInputTrigger(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
参数说明:
参数 | 说明 | 示例 |
TIMx | 所选择的 TIM 外设 |
TIM1 … TIM8 |
TIM_InputTriggerSource | 选择触发源 |
TIM_TS_ITR0 TIM_TS_ITR2 TIM_TS_ITR3 TIM_TS_TI1FP1 TIM_TS_TI2FP2 TIM_TS_ETRF |
6、设置从模式执行的操作
作用:选择触发之后执行的操作。执行Reset操作
void TIM_SelectSlaveMode(TIM_TypeDef* TIMx, uint16_t TIM_SlaveMode);
参数说明:
参数 | 说明 | 示例 |
TIMx | 所选择的 TIM 外设 |
TIM1 … TIM8 |
TIM_SlaveMode | 从模式执行的操作 |
TIM_SlaveMode_Reset TIM_SlaveMode_Trigger TIM_SlaveMode_External1 |
7、开启定时器
TIM_Cmd(TIM4, ENABLE);
8、读取CCR值
TIM_GetCapture1(TIM_TypeDef* TIMx); //获取通道1的计数值
9、PWMI模式
通道1是直连,上升沿触发,把通道2设置成交叉连接,下降沿触发,有专门函数
可实现频率与占空比同时测量
TIM_PWMIConfig(TIM3, &TIM_ICInitStruct);
七、ADC
1、ADC简介
12位逐次逼近型ADC,1us转换时间
输入电压范围:0~3.3V,转换结果:0~4095
18个输入通道,16个GPIO和2个内部信号源
规则组和注入组两个转换单元
2、ADC框图
3、ADC基本结构
3、输入通道
4、转换模式
5、转换时间
STM32 ADC总转换时间:T=采样时间+12.5个ADC周期
ADC最大频率14MHZ,最短转换时间为 T=1.5+12.5=14个ADC周期=1us
6、ADC单通道程序步骤
1、开启RCC时钟,包括ADC和GPIO的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_ADC1, ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
2、配置ADCCLK
void RCC_ADCCLKConfig(uint32_t RCC_PCLK2) //ADCCLK最大14MHZ
参数说明:
参数 | 说明 | 示例 |
RCC_PCLK2 | ADC的频率 |
RCC_PCLK2_Div2 RCC_PCLK2_Div4 RCC_PCLK2_Div6 RCC_PCLK2_Div8 |
3、配置GPIO
作用:将GPIO配置成模拟输入模式
/*GPIO初始化*/
GPIO_InitTypeDef GPIO_InitStructure;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AIN;
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure);
4、配置多路开关,将指定的外部通道接入规则组
void ADC_RegularChannelConfig(ADC_TypeDef* ADCx, uint8_t ADC_Channel, uint8_t Rank, uint8_t ADC_SampleTime);
参数 | 说明 | 示例 |
ADCx | 指定的ADC |
ADC1 ADC2 ADC3 |
ADC_Channel | 指定ADC的通道 |
ADC_Channel_0 … ADC_Channel_17 |
Rank | 规则组序列里的次序 | 1~16 |
SampleTime | 指定通道的采样时间 |
ADC_SampleTime_1Cycles5 ADC_SampleTime_7Cycles5 ADC_SampleTime_13Cycles5 ADC_SampleTime_28Cycles5 ADC_SampleTime_41Cycles5 ADC_SampleTime_55Cycles5 ADC_SampleTime_71Cycles5 ADC_SampleTime_239Cycles5 |
5、配置ADC转换器
作用:配置ADC是单次转换或连续转换,扫描或非扫描模式、通道个数、触发源、数据对齐方式
void ADC_Init(ADC_TypeDef* ADCx, ADC_InitTypeDef* ADC_InitStruct);
参数说明:
参数 | 说明 | 示例 |
ADCx | 指定的ADC |
ADC1 ADC2 ADC3 |
ADC_InitStruct | 指向结构 ADC_InitTypeDef 的指针,包含了ADC的配置信息 |
typedf struct { ADC_Mode; ADC_ScanConvMode; ADC_ContinuousConvMode; ADC_ExternalTrigConv; ADC_DataAlign; ADC_NbrOfChannel; }ADC_InitTypeDef |
6、开启ADC
ADC_Cmd(ADC1,ENABLE);
7、校准ADC
void ADC_ResetCalibration(ADC_TypeDef* ADCx); //开启复位校准
ADC_GetResetCalibrationStatus(ADC_TypeDef* ADCx); //获取复位校准的状态
ADC_StartCalibration(ADC_TypeDef* ADCx); //启动校准
ADC_GetCalibrationStatus(ADC_TypeDef* ADCx); //获取校准状态
8、获取转换值
ADC_SoftwareStartConvCmd(ADC_TypeDef* ADCx, FunctionalState NewState); //软件触发转换
ADC_GetFlagStatus(ADC_TypeDef* ADCx, uint8_t ADC_FLAG); //获取状态标志位
参数说明:
参数 | 说明 | 示例 |
ADCx | 指定的ADC |
ADC1 ADC2 ADC3 |
ADC_FLAG | 想获取的标志位 |
ADC_FLAG_AWD(模拟看门狗标志位) ADC_FLAG_EOC(规则组转换完成标志位,为1时转换完成) ADC_FLAG_JEOC(注入组转换完成标志位) ADC_FLAG_JSTRT(注入组开始转换标志位) ADC_FLAG_STRT(规则组开始转换标志位) |
ADC_GetConversionValue(ADC_TypeDef* ADCx); //获取ADC转换值
八、DMA
1、DMA简介
DMA提供外设和存储器,存储器和存储器之间的高速数据传输,无需CPU干预
12个独立可配置的通道:DMA1(7个通道)、DMA2(5个通道)
每个通道都支持软件触发和特定的硬件触发
2、存储器映像
DMA虽然有多个 通道,但是一次只能转运一个通道
3、DMA基本结构
注意:写传输计数器时,先关闭DMA,在进行
4、DMA工作方式
5、DMA存储器到存储器程序步骤
1、RCC开启DMA的时钟
RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1, ENABLE);
2、配置DMA
作用:初始化外设和存储器的起始地址、数据宽度、地址是否自增、方向、传输计数器、选择触发源等
void DMA_Init(DMA_Channel_TypeDef* DMAy_Channelx, DMA_InitTypeDef* DMA_InitStruct);
参数说明:
参数 | 说明 | 示例 |
DMAy_Channelx | 指定的DMA和通道 |
DMA1_Channel1 … DMA1_Channel7 DMA2_Channel1 … DMA2_Channel5 |
DMA_InitStruct | 指向结构 DMA_InitTypeDef 的指针,包含了DMA的配置信息 |
typedf struct { DMA_PeripheralBaseAddr; DMA_PeripheralDataSize; DMA_PeripheralInc; DMA_MemoryBaseAddr; DMA_MemoryDataSize; DMA_MemoryInc; DMA_BufferSize; DMA_DIR; DMA_M2M; DMA_Mode; DMA_Priority; }DMA_InitTypeDef |
3、给指定DMA通道使能
DMA_Cmd(DMA1_Channel1,ENABLE);
4、再次DMA转运
DMA_Cmd(DMA1_Channel1,DISABLE); //关闭DMA
DMA_SetCurrDataCounter(DMA1_Channel1,MySize); //给传输计时器赋值
DMA_Cmd(DMA1_Channel1,ENABLE); //打开DMA
DMA_GetFlagStatus(uint32_t DMAy_FLAG) //查看标志位,等待转运完成
参数说明:
参数 | 说明 | 示例 |
DMAy_FLAG | 需要查看的标志位 |
DMA1_FLAG_GL1(全局标志位) DMA1_FLAG_TC1(转运完成标志位) DMA1_FLAG_HT1(转运过半标志位) DMA1_FLAG_TE1(转运错误标志位) |
DMA_ClearFlag(uint32_t DMAy_FLAG) //清除转运完成标志位,转运完成置1
6、DMA外设到存储器程序步骤
1、失能外设地址自增
DMA_InitStruct.DMA_PeripheralInc=DMA_PeripheralInc_Disable;
2、选择硬件触发
DMA_InitStruct.DMA_M2M=DMA_M2M_Disable;
3、ADC开启DMA触发信号
ADC_DMACmd(ADC_TypeDef* ADCx, FunctionalState NewState)
九、USART串口通信
1、通信接口
2、电平标准
3、串口参数及时序
4、USART简介
USART是STM32内部集成的硬件外设,可配置数据位长度(8/9)、停止位长度(0.5/1/1.5/2)、校验位(无/偶/奇)
5、串口发送程序步骤
1、开启USART和GPIO的RCC时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //USART1是APB2的外设
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
2、GPIO初始化,把TX配置成复用输出,RX配置成输入
GPIO_InitTypeDef GPIO_InitStruct;
GPIO_InitStruct.GPIO_Mode=GPIO_Mode_AF_PP;
GPIO_InitStruct.GPIO_Pin=GPIO_Pin_9; //PA9是TX引脚
GPIO_InitStruct.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct);
GPIO_InitTypeDef GPIO_InitStruct1;
GPIO_InitStruct1.GPIO_Mode=GPIO_Mode_IPU;
GPIO_InitStruct1.GPIO_Pin=GPIO_Pin_10; //PA10是RX引脚
GPIO_InitStruct1.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_Init(GPIOA,&GPIO_InitStruct1);
3、配置USART
void USART_Init(USART_TypeDef* USARTx, USART_InitTypeDef* USART_InitStruct);
参数说明:
参数 | 说明 | 示例 |
USARTx | 指定的USART |
USART1 USART2 USART3 |
USART_InitStruct | 指向结构 USART_InitTypeDef 的指针,包含了USART的配置信息 |
typedf struct { USART_BaudRate; USART_HardwareFlowControl USART_Mode; USART_Parity; USART_StopBits; USART_WordLength; }USART_InitTypeDef |
4、使能USART
USART_Cmd(USART1,ENABLE);
5、串口常用函数
USART_SendData(USART_TypeDef* USARTx, uint16_t Data); //串口发送
USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG); //获取标志位
参数说明:
参数 | 说明 | 示例 |
USARTx | 指定的USART |
USART1 USART2 USART3 |
USART_FLAG | 指定的标志位 |
USART_FLAG_CTS USART_FLAG_LBD USART_FLAG_TXE(发送寄存器的值转入移位寄存器) USART_FLAG_TC USART_FLAG_RXNE(读寄存器值转入移位寄存器) USART_FLAG_IDLE USART_FLAG_ORE USART_FLAG_NE USART_FLAG_FE USART_FLAG_PE |
USART_ReceiveData(USART1) //接收数据
USART_ITConfig(USART_TypeDef* USARTx, uint16_t USART_IT, FunctionalState NewState);
//串口开启中断
6、USART串口数据包
十、WDG
1、WDG简介
WDG看门狗,当程序出现卡死或跑飞时,看门狗能及时复位程序,保证系统的可靠性和安全性。
看门狗本质上是一个定时器,指定时间范围内,程序没有执行喂狗操作时,即定时器到时间,看门狗硬件就会产生复位信号。
STM32包含:独立看门狗(IWDG):独立工作,对时间精度要求较低
窗口看门狗(WWDG):要求看门狗在精确计时窗口起作用
2、IWDG框图
3、 IWDG键寄存器
4、IWDG超时时间
5、WWDG 框图
6、WWDG工作特性
7、WWDG超时时间
8、IWDG和WWDG对比
9、IWDG程序步骤
1、开启LSI时钟
STM32的LSI时钟通常会在看门狗使能时自动开启,而无需手动干预
2、解除寄存器的写保护
void IWDG_WriteAccessCmd(uint16_t IWDG_WriteAccess)
参数说明:
参数 | 说明 | 示例 |
IWDG_WriteAccess | 使能或失能IWDG |
IWDG_WriteAccess_Enable IWDG_WriteAccess_Disable |
3、写入预分频和重装值
void IWDG_SetPrescaler(uint8_t IWDG_Prescaler)
参数说明:
参数 | 说明 | 示例 |
IWDG_Prescaler | 配置预分频 |
IWDG_Prescaler_4 IWDG_Prescaler_8 IWDG_Prescaler_16 IWDG_Prescaler_32 IWDG_Prescaler_64 IWDG_Prescaler_128 IWDG_Prescaler_256 |
void IWDG_SetReload(uint16_t Reload)
参数说明:
参数 | 说明 | 示例 |
Reload | 配置重装值 |
0~0FFF |
4、启动独立看门狗
IWDG_Enable(void)
5、喂狗
IWDG_ReloadCounter(void)
10、WWDG程序步骤
1、开启窗口看门狗APB1时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE);
2、配置预分频器、窗口值寄存器
void WWDG_SetPrescaler(uint32_t WWDG_Prescaler); //设置预分频
参数说明:
参数 | 说明 | 示例 |
Prescaler | 配置预分频 |
WWDG_Prescaler_1 WWDG_Prescaler_2 WWDG_Prescaler_4 WWDG_Prescaler_8 |
void WWDG_SetWindowValue(uint8_t WindowValue); //配置上窗口值
参数说明:
参数 | 说明 | 示例 |
WindowValue | 配置窗口上限 |
>0x3F <0x80 |
3、使能WWDG
WWDG_Enable(uint8_t Counter);
参数说明:
参数 | 说明 | 示例 |
Counter | 配置计数器值 |
>0x3F <0x80 |
4、喂狗
void WWDG_SetCounter(uint8_t Counter)
十一、RTC实时时钟
1、Unix时间戳
unix时间戳是一个从1970年1月1日0时0分0秒开始到现在经过的秒数
2、BKP简介
BKP(备份寄存器),当主电源VDD断电,可以由VBAT(备用电源)维持供电。当系统在待机模式下被唤醒,或系统复位,BKP的值不会复位。
3、BKP基本结构
4、RTC简介
• RTC(实时时钟),是一个独立定时器,为系统提供时钟和日历
• RTC和时钟配置系统处于后备区域,系统复位数据不清零。
• 32位的可编程计数器,对应Unix时间戳的秒计数器
• 20位的可编程预分频器,适配不同频率的输入时钟
• 可选择三种RTC时钟源:
HSE时钟/128 (8MHZ/128)
LSE振荡器时钟(32.768KHZ)
LSI振荡器时钟(40KHZ)
5、RTC框图
6、RTC基本结构
7、读写BKP寄存器程序步骤
1、开启PWR和BKP时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);
2、使用PWR的函数,使能对BKP和RTC的访问
void PWR_BackupAccessCmd(FunctionalState NewState);
3、写入BKP函数
void BKP_WriteBackupRegister(uint16_t BKP_DR, uint16_t Data);
参数说明:
参数 | 说明 | 示例 |
BKP_DR | 需要写入的BKP的DR寄存器 |
BKP_DRx |
4、读取BKP函数
uint16_t BKP_ReadBackupRegister(uint16_t BKP_DR);
8、RTC实时时钟程序步骤
1、开启PWR和BKP时钟,使能对BKP和RTC的访问
RCC_APB1PeriphClockCmd(RCC_APB1Periph_PWR,ENABLE);
RCC_APB1PeriphClockCmd(RCC_APB1Periph_BKP,ENABLE);
PWR_BackupAccessCmd(ENABLE);
2、启动RTC的时钟
作用:开启LSE时钟
void RCC_LSEConfig(uint8_t RCC_LSE)
RCC_GetFlagStatus(RCC_FLAG_LSERDY) //获取LSE标志位
参数说明:
参数 | 说明 | 示例 |
RCC_LSE | 开启或关闭LSE外部晶振 |
RCC_LSE_OFF RCC_LSE_ON RCC_LSE_Bypass |
3、配置RTCCLK数据选择器,指定LSE为RTCCLK
void RCC_RTCCLKConfig(uint32_t RCC_RTCCLKSource)
参数说明:
参数 | 说明 | 示例 |
RCC_RTCCLKSource | 指定RTC的时钟源 |
RCC_RTCCLKSource_LSE RCC_RTCCLKSource_LSI RCC_RTCCLKSource_HSE_Div128 |
4、使能时钟
RCC_RTCCLKCmd(ENABLE);
5、等待时钟同步
void RTC_WaitForSynchro(void)
5、等待RTC寄存器上一次写操作完成
RTC_WaitForLastTask();
6、设置预分频器
void RTC_SetPrescaler(uint32_t PrescalerValue)
7、配置CNT计数器的值
void RTC_SetCounter(uint32_t CounterValue)
8、读取计数器值
RTC_GetCounter()
9、时间戳转换
作者:qq_52885172