赞
踩
目录
1.void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);
2.void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
3.void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
1.void GPIO_DeInit(GPIO_TypeDef* GPIOx);
3.void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct);
4.void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct);
5.void GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
6.void GPIO_ResetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
7.void GPIO_WriteBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin, BitAction BitVal);
8.void GPIO_Write(GPIO_TypeDef* GPIOx, uint16_t PortVal);
9.uint8_t GPIO_ReadInputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
10.uint16_t GPIO_ReadInputData(GPIO_TypeDef* GPIOx);
11.uint8_t GPIO_ReadOutputDataBit(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
12.uint16_t GPIO_ReadOutputData(GPIO_TypeDef* GPIOx);
13.void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
2.void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
3.void GPIO_EventOutputCmd(FunctionalState NewState);
4.void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState);
5.void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource);
2.void EXTI_Init(EXTI_InitTypeDef* EXTI_InitStruct);
3.void EXTI_StructInit(EXTI_InitTypeDef* EXTI_InitStruct);
4.void EXTI_GenerateSWInterrupt(uint32_t EXTI_Line);
5.FlagStatus EXTI_GetFlagStatus(uint32_t EXTI_Line);
6.void EXTI_ClearFlag(uint32_t EXTI_Line);
7.ITStatus EXTI_GetITStatus(uint32_t EXTI_Line);
8.void EXTI_ClearITPendingBit(uint32_t EXTI_Line);
1.void NVIC_PriorityGroupConfig(uint32_t NVIC_PriorityGroup);
2.void NVIC_Init(NVIC_InitTypeDef* NVIC_InitStruct);
3.void NVIC_SetVectorTable(uint32_t NVIC_VectTab, uint32_t Offset);
4.void NVIC_SystemLPConfig(uint8_t LowPowerMode, FunctionalState NewState);
1.void TIM_DeInit(TIM_TypeDef* TIMx);
2. void TIM_TimeBaseInit(TIM_TypeDef* TIMx, TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
3.void TIM_TimeBaseStructInit(TIM_TimeBaseInitTypeDef* TIM_TimeBaseInitStruct);
4.void TIM_Cmd(TIM_TypeDef* TIMx, FunctionalState NewState);
5.void TIM_ITConfig(TIM_TypeDef* TIMx, uint16_t TIM_IT, FunctionalState NewState);
6.void TIM_InternalClockConfig(TIM_TypeDef* TIMx);
7.void TIM_ITRxExternalClockConfig(TIM_TypeDef* TIMx, uint16_t TIM_InputTriggerSource);
12.void TIM_PrescalerConfig(TIM_TypeDef* TIMx, uint16_t Prescaler, uint16_t TIM_PSCReloadMode);
13.void TIM_CounterModeConfig(TIM_TypeDef* TIMx, uint16_t TIM_CounterMode);
14.void TIM_ARRPreloadConfig(TIM_TypeDef* TIMx, FunctionalState NewState);
15.void TIM_SetCounter(TIM_TypeDef* TIMx, uint16_t Counter);
16.void TIM_SetAutoreload(TIM_TypeDef* TIMx, uint16_t Autoreload);
17.uint16_t TIM_GetCounter(TIM_TypeDef* TIMx);
18.uint16_t TIM_GetPrescaler(TIM_TypeDef* TIMx);
RCC AHB外设时钟控制,使能或者失能AHB外设时钟。
第一个参数就是选择哪个外设,STM32互联网型设备可以在下图列表选择:
其他设备在这个下图选择:
第二个参数就是ENABLE or DISABLE。
RCC APB2外设时钟控制,使能或者失能APB2外设时钟。
第一个参数选择外设,下图是可选择的外设。
第二个参数使能或使能。
在STM32中,所有的GPIO都是挂载在APB2外设总线上的,所以要给PA0端口低电平点亮LED,需要给RCC_APB2外设时钟使能,第一个参数就选择RCC_APB2Periph_GPIOA,第二个参数为ENABLE。
- RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);
- //将APB2总线上挂着的外设GPIOA时钟打开
RCC APB1外设时钟控制,使能或者失能APB1外设时钟。
第一个参数选择外设,下图是可选择的外设。
第二个参数使能或使能。
参数可以写GPIOA、GPIOB等等,调用这个函数后,所指定的GPIO外设就会被复位。
可以复位AFIO外设。
这个函数的作用是,用结构体的参数来初始化GPIO口。
我们需要先定义一个结构体变量,然后再给结构体赋值,最后调用这个函数,这个函数内部就会自动读取结构体的值,然后自动把外设的各个参数配置好。
第一个参数是要初始化的GPIO口,第二个参数是一个结构体。
- GPIO_InitTypeDef GPIO_InitStructure; //定义结构体变量
- GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //GPIO模式选择
- GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //GPIO引脚选择
- GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //GPIO传输速度选择
- GPIO_Init(GPIOA, &GPIO_InitStructure); //调用Init函数
这里的结构体就是一个数据打包的过程,首先将参数写到结构体的三个变量里,然后统一打包,将结构体传递到初始化函数里,接着在初始化函数里面,再把这个结构体拆包出来,读取变量,这就是使用结构体的整个过程。
第一行中GPIO_InitTypeDef是结构体的类型,GPIO_InitStructure是结构体的名字,这里结构体实际上也是一种局部变量。
在第二行,复制结构体名字,然后用“.”把结构体的成员都引出来;
通过在GPIO_Mode右键跳转,可以看到参数说明,在参数GPIOMode_TypeDef选中,Ctrl+F搜索一下,就能看到GPIO的8种工作模式,这里我们选择GPIO_Mode_Out_PP推挽输出模式。
- GPIO_Mode_AIN = 0x0, //模拟输入
- GPIO_Mode_IN_FLOATING = 0x04, //浮空输入
- GPIO_Mode_IPD = 0x28, //下拉输入
- GPIO_Mode_IPU = 0x48, //上拉输入
- GPIO_Mode_Out_OD = 0x14, //开漏输出
- GPIO_Mode_Out_PP = 0x10, //推挽输出
- GPIO_Mode_AF_OD = 0x1C, //复用开漏
- GPIO_Mode_AF_PP = 0x18 //复用推挽
第三行引脚选择,通过在GPIO_Pin右键跳转,在选中GPIO_pins_define 参数处Ctrl+F搜索,就能找到引脚定义,这里我们用的是GPIOA外设的0号引脚,所以选择GPIO_Pin_0。
第四行同理,能找到引脚的输出速度定义,这里我们选则50MHz即可。
第5行就是调用GPIO_Init函数,然后第一个参数写GPIOA,然后GPIO初始化结构体的地址放到GPIO_Init的第二个参数,这样初始化就完成了,GPIO_Init函数执行完,这个GPIOA外设的0号引脚就自动被配置为推挽输出,50MHz的速度了。接下来就可以使用GPIO的这些输入输出函数了。
它内部的主要执行逻辑就是读取结构体的参数,执行一堆判断和运算,最后写入到GPIO配置寄存器。
在GPIO_InitStructure.GPIO_Pin引脚选择中,如果要同时控制一个GPIO外设的多个引脚,可以在
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0 | GPIO_Pin_1 | GPIO_Pin_2 ...,让要控制的引脚都按位“或”,这样其他引脚也就都被选中了。
这是因为GPIO0的引脚0对应数据为0x0001,换成二进制为0000 0000 0000 0001;
GPIO1的引脚0对应数据为0x0002,换成二进制为0000 0000 0000 0010;
GPIO2的引脚0对应数据为0x0004,换成二进制为0000 0000 0000 0100;
GPIO3的引脚0对应数据为0x0008,换成二进制为0000 0000 0000 1000;
等等以此类推,每个端口都对应一个位,将它们按位“或”了以后,就变成了0000 0000 0000 1111,这样就相当于同时选中了3个端口,这就是按位或的操作逻辑。
当然也可以直接用GPIO_Pin_ALL,它对应数据就是0xFFFF,也就是所有位都为1,这样就相当于选中了所有的引脚。
这里除了GPIO_Pin可以用按位或的操作方式外,
RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
时钟控制(红色字体部分)的这一项,也是可以用按位或的操作方式来选择多个外设的。
GPIO_SetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
GPIO_ReSetBits(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin);
函数红色字体部分都可以用按位或选择多个引脚。
这个函数可以把结构体变量赋一个默认值。
以下这四个函数是GPIO的写入函数。
这个函数可以把指定的端口设置为高电平。
第一个参数是GPIOx,第二个参数是GPIO_Pin。
- GPIO_SetBits(GPIOA, GPIO_Pin_0);
- //将PA0口设置为高电平
这个函数可以把指定的端口设置为低电平。
第一个参数是GPIOx,第二个参数是GPIO_Pin。
- GPIO_ResetBits(GPIOA, GPIO_Pin_0);
- //将PA0口设置为低电平
前两个参数都是指定端口,第三个参数是BitVal,根据第三个参数的值来设置指定端口。
第三个参数:
Bit_RESET:清除端口值,也就是置低电平;
Bit_SET:设置端口值,也就是置高电平。
- GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
- //给GPIOA中的0号引脚写入低电平(点亮LED)
第一个参数是GPIOx,第二个参数是PortVal,这个函数可以同时对16个端口进行写入操作,它可以直接写到GPIO的ODR寄存器里。
- GPIO_Write(GPIOA, ~0x0001);
- //对应二进制0000 0000 0000 0001
- //这16个二进制分别对应PA0口导PA15总共16个端口
- //最低位对应PA0,然后往上依次是PA1、PA2,一直到PA15
- //因为是低电平点亮,所以前面加一个按位取反符号~
- //这样就是第一个LED点亮,其他都熄灭。
以下四个函数是GPIO的读取函数。
这个函数是用来读取输入数据寄存器某一个端口的输入值,参数是GPIOx和GPIO_Pin,用来指定某一个端口。
返回值是uint8_t,代表这个端口的高低电平。
这个函数比上一个函数少了一个Bit,它是用来读取整个输入数据寄存器的,参数只有一个GPIOx,用来指定外设。
返回值是uint16_t,是一个16位的数据,每一位代表一个端口值。
这个函数是用来读取输出数据寄存器的某一位,所以它并不是用来读取端口的输入数据的,这个函数一般用于输出模式下,用来看一下自己输出的是什么。
这个函数比上一个函数少了一个Bit,是用来读取整个输出寄存器的。
这个函数是用来锁定GPIO配置的,调用这个函数,参数指定某个引脚,那这个引脚的配置就会被锁定,防止意外更改。
这个函数是用来复位AFIO外设的,调用一下这个函数,AFIO外设的配置就会全部清除。
用来配置AFIO的事件输出功能
用来配置AFIO的事件输出功能
用来进行引脚重映射,第一个参数可以选择要重映射的方式,第二个参数是新的状态。
调用这个函数,就可以配置AFIO的数据选择器,来选择我们想要的中断引脚。
第一个参数是选择某个GPIO外设作为外部中断源,这个参数可以是GPIO_PortSourceGPIOx,其中x是A~G。
第二个参数是GPIO_PinSourcex,指定要配置的外部中断线,其中x是0~15。
- GPIO_EXTILineConfig(GPIO_PortSourceGPIOB, GPIO_PinSource14);
- //AFIO外部中断引脚选择配置
第一个参数是选择GPIOB作为外部中断源,第二个参数表示选择EXTI连接PB14号口的第14个中断线路。
调用这个函数,就可以把EXTI的配置都清除,恢复成上电时默认的状态。
调用这个函数,就可以根据这个结构体里的参数来配置EXTI外设,来初始化EXIT,使用方法和GPIO类似。
- EXTI_InitTypeDef EXTI_InitStructure;
- EXTI_InitStructure.EXTI_Line = EXTI_Line14; //要配置的中断线
- EXTI_InitStructure.EXTI_LineCmd = ENABLE; //指定选择中断线的新状态
- EXTI_InitStructure.EXTI_Mode = EXTI_Mode_Interrupt; //外部中断线的模式
- EXTI_InitStructure.EXTI_Trigger = EXTI_Trigger_Falling; //中断触发方式选择
- EXTI_Init(&EXTI_InitStructure );
这里的结构体参数有四个,作用分别为:
EXTI_Line,是选择配置的中断线,由于我们使用的是PB14,所以需要用到EXTI14中断线,共有20根中断线可以选择。
EXTI_LineCmd,指定选择中断线的新状态,可以选择ENABLE和DISABLE,这里我们是要配置中断,所以肯定是要选择ENABLE。
EXTI_Mode,外部中断线的模式,有中断响应和事件响应两种,这里我们要让CPU执行中断,因此选择中断响应EXTI_Mode_Interrupt。
EXTI_Trigger,中断触发方式选择,有四种,分别是上升沿、下降沿、双边沿,因为之前的GPIO口是选的上拉模式,即没信号影响的时候那个口是高电平,那有信号来的就对应的是电平从高到低,即下降沿,因此我们这里选择下降沿触发EXTI_Trigger_Falling。
在对射式红外传感器计次程序中,下降沿触发是在移开挡光片的时候触发中断,如果是上升沿触发,则是放入挡光片的时候触发中断,如果是双边沿触发,则放入挡光片和移开挡光片的时候都会触发中断,也就是放一次挡光片就会触发两次中断。
调用这个函数,可以把参数传递的结构体变量EXTI_InitStruct,赋一个默认值,
这个函数是用软件来触发外部中断的,调用这个函数,参数给一个指定的中断线,就能软件触发一次这个外部中断。
在外设运行过程中,会产生一些状态标志位,比如外部中断来了,会在挂起寄存器使一个标志位置1,对于其他外设,如串口收到数据,也会置标志位,定时器时间到,也会置标志位,这些标志位都是放在状态寄存器内的,当程序想要看到这些标志位时,就可以用到下面四个函数。
可以获取指定的标志位是否被置1了。
可以对置1的标志位进行清除。
如果想在主程序查看和清除标志位,就用上面两个函数。
对于有些比较紧急的标志位,在置标志位后,会触发中断,在中断函数中,如果想查看标志位和清除标志位,那就用下面两个函数。
获取中断标志位是否被置1。
EXTI_GetITStatus(EXTI_Line14);
上面代码就是查看EXTI14的中断标志位是否为1,返回值是SET or RESET,若返回值是SET,则说明EXTI14的中断标志位为1,若返回值是RESET,说明EXTI14的中断标志位还是为0。
清除中断挂起标志位。
EXTI_ClearITPendingBit(EXTI_Line14)
在每次中断程序结束后,一定要再调用一下清除中断标志位的函数,因为只要中断标志位置1了,程序就会跳转到中断函数, 如果不清除中断标志位,那它就会一直申请中断,这样程序就会不断响应中断,执行中断函数,那程序就会卡死在中断函数中,所以每次中断程序结束后,都应该清除一下中断标志位。
上面这段程序的作用就是清除EXTI14的中断标志位。
这个函数是用来中断分组的,参数是中断分组的方式。
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2); //中断优先级分组
- NVIC_InitTypeDef NVIC_InitStructure;
- NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //选择指定通道
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //开启指定通道
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //给响应优先级分配优先级程度
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //给抢占优先级分配优先级程度
- NVIC_Init(&NVIC_InitStructure);
函数简介是配置优先级分组:抢占优先级和响应优先级
参数可以选择NVIC_PriorityGroup_0~4,共有5种分组情况,如果中断不多,很难导致中断冲突,对优先级分组来说,哪个分组情况都可以,这里选择第三个分组,也就是NVIC_PriorityGroup_2,2位抢占,2位响应,比较平均一些。
注意:分组方式整个芯片只能用一种,所以这个分组的代码,整个工程只需要执行一次就好了,如果在模块里面进行分组,要确保每个模块分组都选的是同一个,或者也可以把这个分组代码放在主函数的最开始,这样模块里就不用再分组了。
根据结构体里面指定的参数初始化NVIC。
- NVIC_InitTypeDef NVIC_InitStructure;
- NVIC_InitStructure.NVIC_IRQChannel = EXTI15_10_IRQn; //选择指定通道
- NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //开启指定通道
- NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //给响应优先级分配优先级程度
- NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1; //给抢占优先级分配优先级程度
- NVIC_Init(&NVIC_InitStructure);
这里的结构体参数有四个,作用分别为:
NVIC_IRQChannel,选择指定通道,它的通道列表在STM32F10x.h文件里,STM32单片机芯片是MD中等密度的,因此找到STM32F10x_MD,往下翻,就能看到EXTI15_10_IRQn中断通道,STM32的EXTI10到EXTI15都是合并到了这个通道里。
IRQChannelCmd,使能或失能指定通道,这里我们肯定是要打开中断通道的,因此我们选择ENABLE。
NVIC_IRQChannelSubPriority,给响应优先级分配优先级程度,这里我们中断分组是2,因此响应优先级和抢占优先级的取值范围都是0~3,有因为中断只有一个,所以取值1即可。
NVIC_IRQChannelPreemptionPriority,给抢占优先级分配优先级程度,取值1。
设置中断向量表。
系统低功耗配置
恢复缺省配置,意思是把当前的状态或设置恢复到系统的初始默认状态。
时基单元初始化,第一个参数TIMx选择某个定时器,第二个是结构体,里面包含了配置时基单元的一些参数。
- TIM_TimeBaseInitTypeDef TIM_TimeBaseInitStruct;
- TIM_TimeBaseInitStruct.TIM_ClockDivision = TIM_CKD_DIV1; //指定时钟分频
- TIM_TimeBaseInitStruct.TIM_CounterMode = TIM_CounterMode_Up; //计数器模式
- TIM_TimeBaseInitStruct.TIM_Period = 10000 - 1; //自动重装器的值
- TIM_TimeBaseInitStruct.TIM_Prescaler = 7200 - 1; //PSC预分频器的值
- TIM_TimeBaseInitStruct.TIM_RepetitionCounter = 0; //重复计数器的值
- TIM_TimeBaseInit(TIM2, &TIM_TimeBaseInitStruct); //初始化时基单元
TIM_ClockDivision,指定时钟分频,第一个是TIM_CKD_DIV1,1分频,也就是不分频,第二个是2分频,第三个是4分频。
TIM_CounterMode,计数器模式,Up是向上计数,Down是向下计数,后面是三种中央对齐的模式。
TIM_Period,TIM_Prescaler,分别是自动重装器的值和预分频的值,如果我们想要定时1s,定时时间=1/定时频率,也就是定时频率为1Hz,根据公式定时频率=72MHz/(预分频器值+1)/(自动重装值+1),所以预分频器值设为7200-1,自动重装值设为10000-1,即定时频率1Hz=1/72×10^6Hz/7200/10000,PSC预分频器值和ARR自动重装值均为0~65535之间,且这两个值不唯一,在满足上面公式的情况下,都可以。
TIM_RepetitionCounter,重复计数器的值,高级定时器才用到,这里不需要用到,给0。
这个函数可以把结构体变量赋一个默认值。
用来使能计数器, 第一个参数TIMx选择定时器,第二个参数NewState新的状态,也就是使能还是失能,使能就是打开计数器开始计数,失能就是关闭计数器。
TIM_Cmd(TIM2,ENABLE); //启动TIM2定时器
用来使能中断输出信号,第一个参数TIMx选择定时器,第二个参数TIM_IT,选择要配置哪个中断输出,第三个参数NewState新的状态,使能或失能。
使用这个函数后,就开启了更新中断到NVIC的通路。
TIM_ITConfig(TIM2,TIM_IT_Update,ENABLE); //使能中断
第二个参数TIM_IT可以是下面值的任意组合。
Update是更新中断。
选择内部时钟,参数TIMx选择定时器。
- void TIM_InternalClockConfig(TIM2);
- //选择内部时钟来驱动TIM2,不写也是默认内部时钟驱动
选择ITRx其他定时器的时钟,第一个参数TIMx选择定时器,第二个参数TIM_InputTriggerSource,选择要接入哪个其他的定时器。
选择TIx捕获通道的时钟,第一个参数TIMx选择定时器,第二个参数TIM_TIxExternalCLKSource,选择TIx具体的某个引脚,第三个参数TIM_ICPolarity,输入的极性,第四个参数ICFilter滤波器。
对于外部引脚的波形,一般都会有极性选择和滤波器,这样更灵活一些。
选择ETR通过外部时钟模式1输入的时钟,第一个参数TIMx选择定时器,第二个参数IM_ExtTRGPrescaler,外部触发预分频器,这里可以对ETR的外部时钟再提前做一个分频,第三个参数和第四个参数和上面一样,分别是极性和滤波器。
选择ETR通过外部时钟模式2输入的时钟,参数和上面函数一致。
对于ETR输入的外部时钟而言,这两个函数是等效的,它们的参数也是一样的,如果不需要触发输入的功能,那两个函数可以互换。
用来配置ETR引脚的预分频器、极性、滤波器这些参数的。
用来单独写预分频值,第一个参数TIMx选择定时器,第二个参数Prescaler,要写入的预分频值,第三个参数TIM_PSCReloadMode,写入的模式,可以选择是听从安排,在更新事件生效,或者是在写入后,手动产生一个更新事件,让这个值立刻生效。
用来改变计数器的计数模式,第一个参数TIMx选择定时器,第二个参数TIM_CounterMode,选择新的计数器模式。
自动重装器预装功能配置,第一个参数TIMx选择定时器,第二个参数NewState新的状态,使能则是有预装功能,失能则没有预装功能。
给计数器写入一个值,如果想手动给一个计数值,就可以用这个函数。
给自动重装器写入一个值,如果想手动给一个自动重装值,就可以用这个函数。
获取当前计数器的值,如果想看当前计数器计数到哪里了,就可以调用一下这个函数。
获取当前的预分频器的值。
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。