STM32F4系列使用库函数配置基层驱动模块
GPIO配置步骤:
//定义 GPIOx 结构体变量
GPIO_InitTypeDef GPIO_InitStructure;
//使能 GPIOx 时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF|RCC_AHB1Periph_GPIOC, ENABLE);
//填充结构体 配置端口
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;//输出速度为50MHz
//PF6 -- LED1 PF9 -- LED2 PF10 -- LED3
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_6|GPIO_Pin_9|GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_OUT;//模式为输出
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//无上下拉
GPIO_Init(GPIOF, &GPIO_InitStructure);
//PC0 -- LED4
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_Init(GPIOC, &GPIO_InitStructure);
LED1(OFF);LED2(OFF);LED3(OFF);LED4(OFF);
可以一次初始化一个IO组下的多个IO,前提是这些IO口的配置方式一样。
按键配置:
使能按键对应IO口时钟。调用函数:
RCC_AHB1PeriphClockCmd ();//参照GPIO配置过程
初始化IO模式:上拉/下拉输入。调用函数GPIO_Init();和GPIO配置过程一样:
//定义 GPIOx 结构体变量
GPIO_InitTypeDef GPIO_InitStructure;
//使能 GPIOx 时钟
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA|RCC_AHB1Periph_GPIOE, ENABLE);
//填充结构体 配置端口
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz;//输出速度为100MHz
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//模式为输入
//PA0 -- KEY1
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN;//下拉
GPIO_Init(GPIOA, &GPIO_InitStructure);
//PE2 PE3 PE4 -- KEY2 KEY3 KEY4
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4;
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP;//上拉
GPIO_Init(GPIOE, &GPIO_InitStructure);
扫描IO口电平(库函数/寄存器/位操作):
u8 Get_KeyNState(void)//u8 <=> unsigned char
{
if(KEY1_READ)
{
Delay_ms(10);//消抖
if(KEY1_READ)
{
while(KEY1_READ);//松开检测
return KEY1;
}
}
if(KEY2_READ)
{
Delay_ms(20);
if(KEY2_READ)
{
while(KEY2_READ);
return KEY2;
}
}
if(KEY3_READ)
{
Delay_ms(20);
if(KEY3_READ)
{
while(KEY3_READ);
return KEY3;
}
}
if(KEY4_READ)
{
Delay_ms(20);
if(KEY4_READ)
{
while(KEY4_READ);
return KEY4;
}
}
return 0;
}
端口复用配置过程:
①GPIO端口时钟使能。
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE);
②复用外设时钟使能。
//比如你要将端口PA9,PA10复用为串口,所以要使能串口时钟。
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);
③端口模式配置为复用功能。 GPIO_Init()函数。
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
④配置GPIOx_AFRL或者GPIOx_AFRH寄存器,将IO连接到所需的AFx。
/*PA9连接AF7,复用为USART1_TX */
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1);
/* PA10连接AF7,复用为USART1_RX*/
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1);
例子:
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA,ENABLE); //使能GPIOA时钟 ①
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);//使能USART1时钟 ②
//USART1端口配置③
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9 | GPIO_Pin_10; //GPIOA9与GPIOA10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //速度50MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA9,PA10
//串口1对应引脚复用映射 ④
GPIO_PinAFConfig(GPIOA,GPIO_PinSource9,GPIO_AF_USART1); //GPIOA9复用为USART1
GPIO_PinAFConfig(GPIOA,GPIO_PinSource10,GPIO_AF_USART1); //GPIOA10复用为USART1
中断优先级配置过程:
系统运行后先设置中断优先级分组。调用函数:
void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
整个系统执行过程中,只设置一次中断分组即可。
针对每个中断,设置对应的抢占优先级和响应优先级:
void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
如果需要挂起/解挂,查看中断当前激活状态,分别调用相关函数即可。
例子:
typedef struct
{
uint8_t NVIC_IRQChannel; //设置中断通道
uint8_t NVIC_IRQChannelPreemptionPriority;//设置响应优先级
uint8_t NVIC_IRQChannelSubPriority; //设置抢占优先级
FunctionalState NVIC_IRQChannelCmd; //使能/失能
} NVIC_InitTypeDef;
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寄存器
串口配置:
① 串口时钟使能:RCC_APBxPeriphClockCmd();
RCC_AHB1PeriphClockCmd();//GPIO 时钟使能
② 引脚复用映射:
GPIO_PinAFConfig();
③GPIO端口模式设置:GPIO_Init();
/*配置GPIOA模式*/
//PA9 -- MAIN_TX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用模式
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP;//推挽
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_NOPULL;//无上下拉
GPIO_Init(GPIOA,&GPIO_InitStructure);
//PA10 -- MAIN_RX
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN;//浮空输入模式
GPIO_Init(GPIOA,&GPIO_InitStructure);
④串口参数初始化:USART_Init();
/*USART 初始化配置*/
USART_InitStructure.USART_BaudRate = baud;//波特率
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据
USART_InitStructure.USART_StopBits = USART_StopBits_1;//1个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx;//串口模式为发送或接收
USART_Init(USART1,&USART_InitStructure);
⑤开启中断并且初始化NVIC(如果需要开启中断才需要这个步骤):
/*中断控制器NVIC 配置*/
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//使能指定的 IRQ 通道
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 3;//抢占优先级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3;//between 0 and 15
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道使能
NVIC_Init(&NVIC_InitStructure);
/* 使能或者失能指定的 USART 中断 */
//USART_ITConfig(USART1,USART_IT_IDLE, ENABLE);//空闲中断 -- USART_IT_RXNE 接收中断 | USART_IT_TXE 发送中断
USART_ITConfig(USART1,USART_IT_TC, ENABLE);//使能传输完成中断
⑥使能串口:USART_Cmd();
//使能USART1
USART_Cmd(USART1, ENABLE);
⑦编写中断处理函数:USARTx_IRQHandler();
void USART1_IRQHandler(void)
{
if(USART_GetITStatus(USART1, USART_IT_IDLE) != RESET)//USART_IT_IDLE 空闲中断标志位(RESET = 0)
{
//USART1_RX -- DMA1_CH5 -- 对外上位机
USART_ClearITPendingBit(USART1, USART_IT_IDLE);//清除空闲中断标志
}
if(USART_GetITStatus(USART1, USART_IT_TC) != RESET)//传输完成中断标志位
{
USART_ClearITPendingBit(USART1, USART_IT_TC);//清除传输完成中断标志
}
}
⑧串口数据收发:
void USART_SendData();//发送数据到串口,DR
uint16_t USART_ReceiveData();//接受数据,从DR读取接受到的数据
⑨串口传输状态获取:
FlagStatus USART_GetFlagStatus();
void USART_ClearITPendingBit();
外部中断配置:
使能SYSCFG时钟:
RCC_APB2PeriphClockCmd(RCC_APB2Periph_SYSCFG, ENABLE);
初始化IO口为输入。
GPIO_Init();
设置IO口与中断线的映射关系。
void SYSCFG_EXTILineConfig();
初始化线上中断,设置触发条件等。
EXTI_Init();
配置中断分组(NVIC),并使能中断。
NVIC_Init();
编写中断服务函数。
EXTIx_IRQHandler();
清除中断标志位
EXTI_ClearITPendingBit();
例如:
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);
独立看门狗配置过程:
1.取消寄存器写保护:
IWDG_WriteAccessCmd();
2.设置独立看门狗的预分频系数,确定时钟:
IWDG_SetPrescaler();
3.设置看门狗重装载值,确定溢出时间:
IWDG_SetReload();
4.使能看门狗
IWDG_Enable();
5.应用程序喂狗:
IWDG_ReloadCounter();
溢出时间计算:
Tout=((4×2^prer) ×rlr) /32 (M4) 注意单位统一
prep:预分频系数 rlr:重装载值
void IWDG_Init(u8 prer,u16 rlr)
{
IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable);
IWDG_SetPrescaler(prer);
IWDG_SetReload(rlr);
IWDG_ReloadCounter();
IWDG_Enable();
}
主函数中设置中断优先级分组,初始化IO;调用IWDG_Init(4,500); 在while中进行喂狗。
窗口看门狗配置:
1.使能看门狗时钟:
RCC_APB1PeriphClockCmd();
2.设置分频系数:
WWDG_SetPrescaler();
3.设置上窗口值:
WWDG_SetWindowValue();
4.开启提前唤醒中断并分组(可选):
WWDG_EnableIT();
NVIC_Init();
5.使能看门狗:
WWDG_Enable();
6.喂狗:
WWDG_SetCounter();
7.编写中断服务函数
WWDG_IRQHandler();
void WWDG_Init(u8 tr,u8 wr,u32 fprer)
{
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_WWDG,ENABLE); //使能窗口看门狗时钟
WWDG_CNT=tr&WWDG_CNT; //初始化WWDG_CNT.
WWDG_SetPrescaler(fprer); //设置分频值
WWDG_SetWindowValue(wr); //设置窗口值
// WWDG_SetCounter(WWDG_CNT);//设置计数值
WWDG_Enable(WWDG_CNT); //开启看门狗
NVIC_InitStructure.NVIC_IRQChannel=WWDG_IRQn; //窗口看门狗中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0x02; //抢占优先级为2
NVIC_InitStructure.NVIC_IRQChannelSubPriority=0x03; //子优先级为3
NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE; //使能窗口看门狗
NVIC_Init(&NVIC_InitStructure);
WWDG_ClearFlag();//清除提前唤醒中断标志位
WWDG_EnableIT();//开启提前唤醒中断
}
//窗口看门狗中断服务程序
void WWDG_IRQHandler(void)
{
WWDG_SetCounter(WWDG_CNT); //重设窗口看门狗值
WWDG_ClearFlag();//清除提前唤醒中断标志位
LED1=!LED1;
}
定时器中断配置:
1.能定时器时钟。
RCC_APB1PeriphClockCmd();
2.初始化定时器,配置ARR,PSC。
TIM_TimeBaseInit();
3.开启定时器中断,配置NVIC。
NVIC_Init();
4.使能定时器。
TIM_Cmd();
5.编写中断服务函数。
TIMx_IRQHandler();
举例:
//定义 定时器&中断控制器 结构体变量 TIM7 -- 84MHz
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
/*配置定时器*/
//使能TIM7时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM6|RCC_APB1Periph_TIM7, ENABLE);
//设置预分频器值
TIM_TimeBaseStructure.TIM_Prescaler = 42;//预分频系数 84M/42 = 2000000
TIM_TimeBaseStructure.TIM_ClockDivision = TIM_CKD_DIV1;//时钟分割 置为0,不分割即可
//16位重载值(0~65535)
TIM_TimeBaseStructure.TIM_Period = 2;//2*1/2000000 s == 0.001 ms == 1 us
//计数模式
TIM_TimeBaseStructure.TIM_CounterMode = TIM_CounterMode_Up;//向上计数
//初始化定时器6
TIM_TimeBaseInit(TIM6, &TIM_TimeBaseStructure);
//初始化定时器7
TIM_TimeBaseStructure.TIM_Prescaler = 42000;//预分频系数 84M/42k = 2000
TIM_TimeBaseStructure.TIM_Period = 2000;//2000*1/2000 s == 1 s
TIM_TimeBaseInit(TIM7, &TIM_TimeBaseStructure);
/*配置中断控制器NVIC*/
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 4;//先占优先级4级
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;//从优先级1级
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;//IRQ通道被使能
/* Enable the TIM6 gloabal Interrupt */
//使能TIM6全局中断
NVIC_InitStructure.NVIC_IRQChannel = TIM6_DAC_IRQn;//TIM6中断
NVIC_Init(&NVIC_InitStructure);
//使能TIM7全局中断
NVIC_InitStructure.NVIC_IRQChannel = TIM7_IRQn;//TIM7中断
NVIC_Init(&NVIC_InitStructure);
//使能定时器更新中断
TIM_ITConfig(TIM6, TIM_IT_Update, ENABLE);
TIM_ITConfig(TIM7, TIM_IT_Update, ENABLE);//TIM_IT_Update --> TIM 中断源
//关闭计数器(使用时在打开)
TIM_Cmd(TIM6, DISABLE);
TIM_Cmd(TIM7, DISABLE);
pwm输出配置:
1.使能定时器14和相关IO口时钟。
使能定时器14时钟:RCC_APB1PeriphClockCmd();
使能GPIOF时钟:RCC_AHB1PeriphClockCmd ();
2.初始化IO口为复用功能输出。函数:GPIO_Init();
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能
3.GPIOF9复用映射到定时器14
GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14);
4.初始化定时器:ARR,PSC等:TIM_TimeBaseInit();
5.初始化输出比较参数:TIM_OC1Init();
6.使能预装载寄存器: TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable);
7.使能自动重装载的预装载寄存器允许位TIM_ARRPreloadConfig(TIM14,ENABLE);
8.使能定时器。
9.不断改变比较值CCRx,达到不同的占空比效果:TIM_SetCompare1();
void TIM14_PWM_Init(u32 arr,u32 psc)
{
//此部分需手动修改IO口设置
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
TIM_OCInitTypeDef TIM_OCInitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM14,ENABLE); //TIM14时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOF, ENABLE); //使能PORTF时钟
GPIO_PinAFConfig(GPIOF,GPIO_PinSource9,GPIO_AF_TIM14); //GPIOF9复用为定时器14
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //GPIOF9
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF; //复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度100MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_UP; //上拉
GPIO_Init(GPIOF,&GPIO_InitStructure); //初始化PF9
TIM_TimeBaseStructure.TIM_Prescaler=psc; //定时器分频
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM14,&TIM_TimeBaseStructure);//初始化定时器14
//初始化TIM14 Channel1 PWM模式
TIM_OCInitStructure.TIM_OCMode = TIM_OCMode_PWM1; //选择定时器模式:TIM脉冲宽度调制模式2
TIM_OCInitStructure.TIM_OutputState = TIM_OutputState_Enable; //比较输出使能
TIM_OCInitStructure.TIM_OCPolarity = TIM_OCPolarity_Low; //输出极性:TIM输出比较极性低
TIM_OC1Init(TIM14, &TIM_OCInitStructure); //根据T指定的参数初始化外设TIM1 4OC1
TIM_OC1PreloadConfig(TIM14, TIM_OCPreload_Enable); //使能TIM14在CCR1上的预装载寄存器
TIM_ARRPreloadConfig(TIM14,ENABLE);//ARPE使能
TIM_Cmd(TIM14, ENABLE); //使能TIM14
}
输入捕获配置:
① 初始化定时器和通道对应IO的时钟。
② 初始化IO口,模式为复用:GPIO_Init();
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;
③设置引脚复用映射:
GPIO_PinAFConfig();
④初始化定时器ARR,PSC
TIM_TimeBaseInit();
⑤初始化输入捕获通道
TIM_ICInit();
⑥如果要开启捕获中断,
TIM_ITConfig();
NVIC_Init();
⑦使能定时器:TIM_Cmd();
⑧编写中断服务函数:TIMx_IRQHandler();
void TIM5_CH1_Cap_Init(u32 arr,u16 psc)
{
GPIO_InitTypeDef GPIO_InitStructure;
TIM_TimeBaseInitTypeDef TIM_TimeBaseStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB1PeriphClockCmd(RCC_APB1Periph_TIM5,ENABLE); //TIM5时钟使能
RCC_AHB1PeriphClockCmd(RCC_AHB1Periph_GPIOA, ENABLE); //使能PORTA时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIOA0
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF;//复用功能
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_100MHz; //速度100MHz
GPIO_InitStructure.GPIO_OType = GPIO_OType_PP; //推挽复用输出
GPIO_InitStructure.GPIO_PuPd = GPIO_PuPd_DOWN; //下拉
GPIO_Init(GPIOA,&GPIO_InitStructure); //初始化PA0
GPIO_PinAFConfig(GPIOA,GPIO_PinSource0,GPIO_AF_TIM5); //PA0复用位定时器5
TIM_TimeBaseStructure.TIM_Prescaler=psc; //定时器分频
TIM_TimeBaseStructure.TIM_CounterMode=TIM_CounterMode_Up; //向上计数模式
TIM_TimeBaseStructure.TIM_Period=arr; //自动重装载值
TIM_TimeBaseStructure.TIM_ClockDivision=TIM_CKD_DIV1;
TIM_TimeBaseInit(TIM5,&TIM_TimeBaseStructure);
//初始化TIM5输入捕获参数
TIM5_ICInitStructure.TIM_Channel = TIM_Channel_1; //CC1S=01 选择输入端 IC1映射到TI1上
TIM5_ICInitStructure.TIM_ICPolarity = TIM_ICPolarity_Rising; //上升沿捕获
TIM5_ICInitStructure.TIM_ICSelection = TIM_ICSelection_DirectTI; //映射到TI1上
TIM5_ICInitStructure.TIM_ICPrescaler = TIM_ICPSC_DIV1; //配置输入分频,不分频
TIM5_ICInitStructure.TIM_ICFilter = 0x00;//IC1F=0000 配置输入滤波器 不滤波
TIM_ICInit(TIM5, &TIM5_ICInitStructure);
TIM_ITConfig(TIM5,TIM_IT_Update|TIM_IT_CC1,ENABLE);//允许更新中断 ,允许CC1IE捕获中断
TIM_Cmd(TIM5,ENABLE ); //使能定时器5
NVIC_InitStructure.NVIC_IRQChannel = TIM5_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=2;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority =0; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIC寄存器
}