赞
踩
就是像一些功能如:LED灯的点亮,蜂鸣器的启动是需要在代码中经常要用到的。但是如果每次都要在程序中进行复写一遍的话就会十分的麻烦,所以将这些代码进行封装再调用的话代码就会变得十分的方便快捷。把各个模块的代码分别放在.c文件中,在.h文件存放函数外部可调用函数声明,在其他的.c文件想要使用其中的代码时,只需要#include"XXX.h"文件即可
预编译往往以#号开头,在真正编译前对代码进行一些处理。
1.h文件
#ifndef __XXXX_X //X一般后面为大写的文件名,此段意思为如果没有定义的话则执行下面语句
#define __XXXX_X //定义XXXX
#endif //与ifndef对应
2.c文件
一般写具体的函数实现。
中断:在主程序运行过程中,出现了特定的中断触发条件(中断源),使得CPU暂停当前正在运行的程序,转而去处理中断程序,处理完成后又返回原来被暂停的位置继续运行
基本流程为
1.配置RCC时钟,启用相应的GPIO和AFIO。
EXTI与NVIC的时钟不需要RCC时钟开启
示例代码:
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
2.配置GPIO口
- GPIO_InitTypeDef GPIO_InitSturcture;
- GPIO_InitSturcture.GPIO_Mode=GPIO_Mode_IPD;
- GPIO_InitSturcture.GPIO_Pin=GPIO_Pin_0 | GPIO_Pin_1;
- GPIO_InitSturcture.GPIO_Speed=GPIO_Speed_50MHz;
- GPIO_Init(GPIOB,&GPIO_InitSturcture);
3.配置AFIO
AFIO为一个数据选择器,主要是在前面n个GPIO口中挑选一个到EXTI程序中。其代码中为AFIO这四个字母,但是要知道这是配置AFIO的。在STM32中,AFIO主要完成两个任务:复用功能引脚重映射、中断引脚选择
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource0);//为AFIO的初始化程序
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource1);//为AFIO的初始化程序
GPIO_EXTILineConfig功能为配置AFIO的数据选择器来配置我们想要的中断引脚。
上面代码为配置GPIOB 0号和1号口
4.配置EXTI
EXTI(Extern Interrupt)外部中断 EXTI可以监测指定GPIO口的电平信号,当其指定的GPIO口产生电平变化时,EXTI将立即向NVIC发出中断申请,经过NVIC裁决后即可中断CPU主程序,使CPU执行EXTI对应的中断程序
支持的触发方式:上升沿/下降沿/双边沿/软件触发
支持的GPIO口:所有GPIO口,但相同的Pin不能同时触发中断(因为AFIO与EXTI的接口只有十六个,AFIO只能从众多GPIO的接口中挑选一个来接入EXTI,所以像PA0,PB0,PC0等都是不行的)
通道数:16个GPIO_Pin,外加PVD输出、RTC闹钟、USB唤醒、以太网唤醒
触发响应方式:中断响应/事件响应
- EXTI_InitTypeDef EXTI_InitStucture;
- EXTI_InitStucture.EXTI_Line=EXTI_Line0 | EXTI_Line1;//与所选pin口有关,此为第十四个线路
- EXTI_InitStucture.EXTI_LineCmd=ENABLE;//开启中断
- EXTI_InitStucture.EXTI_Mode=EXTI_Mode_Interrupt;//中断触发模式
- EXTI_InitStucture.EXTI_Trigger = EXTI_Trigger_Falling;
- EXTI_Init(&EXTI_InitStucture);
- //配置好后进行初始化,这样PB14的电平信号就能通过EXTI通向下一级NVIC
-
5.配置NVIC
NVIC主要进行中断分配,NVIC只有一个输出口,根据中断的优先级来告诉CPU来先进行那个中断处理
- NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);//中断分组
-
- NVIC_InitTypeDef NVIC_InitStructure;
- NVIC_InitStructure.NVIC_IRQChannel=EXTI0_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
- NVIC_Init(&NVIC_InitStructure);
-
- NVIC_InitStructure.NVIC_IRQChannel=EXTI1_IRQn;
- NVIC_InitStructure.NVIC_IRQChannelCmd=ENABLE;
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;
- NVIC_InitStructure.NVIC_IRQChannelSubPriority=1;
- NVIC_Init(&NVIC_InitStructure);
- }
这里可以看到上面那个配置过的结构体在用过后可以在下面直接用,不用再重新定义。
在stm32中中断函数是固定的,每个中断通道对应一个中断函数,如果写错了中断函数的名字就会进不了中断。
- DCD EXTI1_IRQHandler ; EXTI Line 1
- DCD EXTI2_IRQHandler ; EXTI Line 2
- DCD EXTI3_IRQHandler ; EXTI Line 3
- DCD EXTI4_IRQHandler ; EXTI Line 4
- DCD EXTI9_5_IRQHandler ; EXTI Line 9..5
- DCD EXTI15_10_IRQHandler ; EXTI Line 15..10
其中有一些是共用的,所以要进行中断标志位的判断,确保是我们想要的中断源进入中断函数。
列如:EXTI_GetFlagStatus(EXTI_Line14)==SET,判断是不是EXTI14进入了中断标志位。
在中断结束后一定要清除中断标志位,不然中断标志位置1后会一直申请中断。
- void EXTI15_10_IRQHandler(void)
- {
- if(EXTI_GetFlagStatus(EXTI_Line14)==SET)
- {
- Delay_ms(30);
- sum++;
-
-
- EXTI_ClearITPendingBit(EXTI_Line14);//清除中断标志位,防止死循环
- }
- }
1、上拉输入:IO口在无输入的情况下,保持高电平。
2、下拉输入:IO口在无输入的情况下,保持低电平。
3、浮空输入:浮空输入状态下,IO的电平状态是不确定的,完全由外部输入决定,如果在该引脚悬空的情况下,读取该端口的电平是不确定的。
4、模拟输入:输入信号不经施密特触发器直接接入,输入信号为模拟量而非数字量,其余输入方式输入数字量。
在设置按键的输入模式时由于按键接的是地,所以在按键的GPIO口设置为上拉输入,当按下按键时使GPIO口接地输入低电平。
uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
读取输入数据寄存器某一个端口的输入值,读取按键需要用到此函数
uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
读取整个输入数据寄存器
uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
读取输出数据寄存器,一般看自己输出的是什么。
uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
读取整个输出数据寄存器
像输入外设一般近似于按键,所以在GPIO口的模式设置中可以与按键的模式一致,如光敏传感器,而输出可以像LED,如蜂鸣器。
1.OLED基本函数
OLED显示屏一共有六行十六列字符框
定时器可以对输入的时钟进行计数,并在计数值达到设定值时触发中断
16位计数器、预分频器、自动重装寄存器的时基单元,在72MHz计数时钟下可以实现最大59.65s的定时
不仅具备基本的定时中断功能,而且还包含内外时钟源选择、输入捕获、输出比较、编码器接口、主从触发模式等多种功能 根据复杂度和应用场景分为了高级定时器、通用定时器、基本定时器三种类型
在开启时钟时要选择正确的总线,如通用定时器总线为APB1,则时钟开启函数为RCC_APB1PeriphClockCmd
实际分频系数=预分频器的值+1,最大值可以设置为65535,即65536次分频。
计数器为十六位的,可以从0加到65535,计数时钟每来一个上升沿计数器就加1。当加到目标值就会产生中断。在通用中还可从目标值向下自减。
主要是存储要计数的目标,当计数器的计数值等于重装值时,就是计时时间到了,会产生一个中断信号。并且清零计数器。
只需要将上面的每个模块都打通(即完成每个模块的初始化)就可以让定时器工作了。
TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
用来配置时基单元
TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
把结构体变量赋一个默认值
4.2 运行控制
TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
使能计数器,对应上图中的运行控制
4.3 中断输出控制
TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
使能中断输出信号
4.4 时钟源选择
TIM_InternalClockConfig(TIM_TypeDef* TIMx);
选择内部时钟
TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
选择ITRX其他定时器时钟
- TIM_TIxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_TIxExternalCLKSource,
- uint16_t TIM_ICPolarity, uint16_t ICFilter);
选择Tlx具体的某个引脚
TIM_ETRClockMode1Config(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,int16_t ExtTRGFilter);
选择ETR通过外部时钟模式1输入的时钟,还有TIM_ETRClockMode2Config外部触发输入,TIM_ETRClockMode1Config为外部输入
void TIM_ETRConfig(TIM_TypeDef* TIMx, uint16_t TIM_ExtTRGPrescaler, uint16_t TIM_ExtTRGPolarity,uint16_t ExtTRGFilter);
单独配置ETR引脚的预分频器,极性,滤波器这些参数
内部时钟:是可以自己进行计数跳变的,不需要其他触发条件,设置好后自动进行数字增加。
外部时钟:当接入外部时钟时,计数器接受外部的脉冲信号,列如当外部时钟为按键时,只有在按下按键时时钟才会进行增加。
输出比较可以通过比较CNT与CCR寄存器值的关系,来对输出电平进行置1、置0或翻转的操作,用于输出一定频率和占空比的PWM波形
有效电平=高电平 无效电平=低电平
在具有惯性的系统中,可以通过对一系列脉冲的宽度进行调制,来等效地获得所需要的模拟参量,常应用于电机控速等领域
PWM参数:
频率 = 1 / TS 占空比 = TON / TS (高电平时间比总时间) 分辨率 = 占空比变化步距
黄线:ARR 蓝线:CNTDSZ ES W 红线:CCR 绿线:电平
PWM频率: Freq = CK_PSC / (PSC + 1) / (ARR + 1)
PWM占空比: Duty = CCR / (ARR + 1)
PWM分辨率: Reso = 1 / (ARR + 1)
void TIM_OC1Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC2Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC3Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
void TIM_OC4Init(TIM_TypeDef* TIMx, TIM_OCInitTypeDef* TIM_OCInitStruct);
用来配置输出比较模块(O=output C=Compare),由于存在复用所以OC1只能对应PA0,就是说使用OC1使只能使用PA0输出,OC2只能使用PA1输出,OC3对应PA2,OC4对应PA3
void TIM_OCStructInit(TIM_OCInitTypeDef* TIM_OCInitStruct);
给输出比较模块赋一个默认值,因为在进行结构体配置是不一定会用到所有的结构体,就意味着有些结构体不会被配置处于不确定状态,有可能会导致一些错误,而这个函数就是直接先把所有的结构体赋值防止出现错误。
void TIM_SetCompare1(TIM_TypeDef* TIMx, uint16_t Compare1);
单独更改CCR的值。
void TIM_SetCompare2(TIM_TypeDef* TIMx, uint16_t Compare2);
void TIM_SetCompare3(TIM_TypeDef* TIMx, uint16_t Compare3);
void TIM_SetCompare4(TIM_TypeDef* TIMx, uint16_t Compare4);
单独更改CCR寄存器的函数,在运行时更改占空比。
在配置好PWM后使用到GPIO口用来输出配置好的GPIO信号,所以GPIO也要进行初始化。
IC(Input Capture)输入捕获
输入捕获模式下,当通道输入引脚出现指定电平跳变时,当前CNT的值将被锁存到CCR中,可用于测量PWM波形的频率、占空比、脉冲间隔、电平持续时间等参数
每个高级定时器和通用定时器都拥有4个输入捕获通道
可配置为PWMI模式,同时测量频率和占空比
可配合主从触发模式,实现硬件全自动测量
编码器接口可接收增量(正交)编码器的信号,根据编码器旋转产生的正交信号脉冲,自动控制CNT自增或自减,从而指示编码器的位置、旋转方向和旋转速度
两个输入引脚借用了输入捕获的通道1和通道2
降低软件资源的浪费,使硬件进行自增或自减
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。