赞
踩
寄存器就是一段特殊的存储器,内核可以通过APB2总线对寄存器进行读写,完成输出电平和读取电平的功能了。寄存器的每一位对应一个引脚,其中输出寄存器写1,对应的引脚就会输出高电平;写0,就会输出低电平。输入寄存器读取为1,就证明对应的端口目前是高电平,读取为0,就是低电平。因为STM32是32位的单片机,所以STM32内部的寄存器都是32位的,但这个端口只有16位,所以这个寄存器只有低16位对应的端口,高16位是没有用到的。这个驱动器是用来增加信号的驱动能力的,寄存器只负责存储数据如果要进行点灯这样的操作的话,还是需要驱动器来负责增大驱动能力,这些就是GPIO的整体基本结构。
下图为GPIO位结构的电路图
可以分为上下两个部分:输入和输出部分
CNF=端口的配置位
MODE=端口的配置位
当I/O端口配置为输入时:
● 输出缓冲器被禁止
● 施密特触发输入被激活
● 根据输入配置(上拉,下拉或浮动)的不同,弱上拉和下拉电阻被连接
● 出现在I/O脚上的数据在每个APB2时钟被采样到输入数据寄存器
● 对输入数据寄存器的读访问可得到I/O状态
当I/O端口被配置为模拟输入配置时:
● 输出缓冲器被禁止;
● 禁止施密特触发输入,实现了每个模拟I/O引脚上的零消耗。施密特触发输出值被强置
为’0’;
● 弱上拉和下拉电阻被禁止;
● 读取输入数据寄存器时数值为’0’。
当I/O端口被配置为输出时:
● 输出缓冲器被激活
─ 开漏模式:输出寄存器上的’0’激活N-MOS,而输出寄存器上的’1’将端口置于高阻状态(PMOS从不被激活)。
─ 推挽模式:输出寄存器上的’0’激活N-MOS,而输出寄存器上的’1’将激活P-MOS。
● 施密特触发输入被激活
● 弱上拉和下拉电阻被禁止
● 出现在I/O脚上的数据在每个APB2时钟被采样到输入数据寄存器
● 在开漏模式时,对输入数据寄存器的读访问可得到I/O状态
● 在推挽式模式时,对输出数据寄存器的读访问得到最后一次写的值。
当I/O端口被配置为复用功能时:
● 在开漏或推挽式配置中,输出缓冲器被打开
● 内置外设的信号驱动输出缓冲器(复用功能输出)
● 施密特触发输入被激活
● 弱上拉和下拉电阻被禁止
● 在每个APB2时钟周期,出现在I/O脚上的数据被采样到输入数据寄存器
● 开漏模式时,读输入数据寄存器时可得到I/O口状态
● 在推挽模式时,读输出数据寄存器时可得到最后一次写的值
其他可以参考STM32的参考手册8 通用和复用功能I/O(GPIO和AFIO)
使用STM32的GPIO口驱动LED的电路如下,分别为低电平驱动的电路和高电平驱动的电路
由于很多单片机都使用了高电平弱驱动,低电平的强驱动的规则,所以一般倾向于使用低电平驱动的电路
使用STM32的GPIO口驱动蜂鸣器的电路如下,这里使用了三极管开关的驱动方案,分别是PNP三极管和NPN三极管
新建工程或直接复制工程模板,并且可以把批处理文件keilkill.bat(可以把工程编译产生的中间文件都删除)复制到工程文件夹中。
连接线路,将所需要的器件连接到面包板上
操作STM32的GPIO
void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState);
void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState);
void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState);
RCC_AHB外设时钟控制、RCC_APB2外设使用控制、RCC_APB2外设使用控制。我们可以右键跳到定义,这时就来到了.C文件里的函数定义,上面这有一个函数的介绍,这个AHB外设时钟控制的函数就是使能或者失能AHB的外设时钟的,下面介绍第一个参数就是选择哪个外设,这里说STM32互联型的设备可以在这个列表选择,其他设备在下面这个列表选择;接着第二个参数就是enable或者disable,然后下面的AHB2外设时钟控制和AHB1外设时钟控制都是一样的操作方法,第一个参数选择外设,第二个参数使能或失能,如果你不清楚哪个外设是连接在哪个总线上的,还可以在注释的列表找一下,列表中出现的就肯定是这个总线的外设,这就是RCC的介绍,最主要的就是这三个函数。
/** * @brief Enables or disables the AHB peripheral clock. * @param RCC_AHBPeriph: specifies the AHB peripheral to gates its clock. * * For @b STM32_Connectivity_line_devices, this parameter can be any combination * of the following values: * @arg RCC_AHBPeriph_DMA1 * @arg RCC_AHBPeriph_DMA2 * @arg RCC_AHBPeriph_SRAM * @arg RCC_AHBPeriph_FLITF * @arg RCC_AHBPeriph_CRC * @arg RCC_AHBPeriph_OTG_FS * @arg RCC_AHBPeriph_ETH_MAC * @arg RCC_AHBPeriph_ETH_MAC_Tx * @arg RCC_AHBPeriph_ETH_MAC_Rx * * For @b other_STM32_devices, this parameter can be any combination of the * following values: * @arg RCC_AHBPeriph_DMA1 * @arg RCC_AHBPeriph_DMA2 * @arg RCC_AHBPeriph_SRAM * @arg RCC_AHBPeriph_FLITF * @arg RCC_AHBPeriph_CRC * @arg RCC_AHBPeriph_FSMC * @arg RCC_AHBPeriph_SDIO * * @note SRAM and FLITF clock can be disabled only during sleep mode. * @param NewState: new state of the specified peripheral clock. * This parameter can be: ENABLE or DISABLE. * @retval None */ void RCC_AHBPeriphClockCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState) { /* Check the parameters */ assert_param(IS_RCC_AHB_PERIPH(RCC_AHBPeriph)); assert_param(IS_FUNCTIONAL_STATE(NewState)); if (NewState != DISABLE) { RCC->AHBENR |= RCC_AHBPeriph; } else { RCC->AHBENR &= ~RCC_AHBPeriph; } } /** * @brief Enables or disables the High Speed APB (APB2) peripheral clock. * @param RCC_APB2Periph: specifies the APB2 peripheral to gates its clock. * This parameter can be any combination of the following values: * @arg RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB, * RCC_APB2Periph_GPIOC, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE, * RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG, RCC_APB2Periph_ADC1, * RCC_APB2Periph_ADC2, RCC_APB2Periph_TIM1, RCC_APB2Periph_SPI1, * RCC_APB2Periph_TIM8, RCC_APB2Periph_USART1, RCC_APB2Periph_ADC3, * RCC_APB2Periph_TIM15, RCC_APB2Periph_TIM16, RCC_APB2Periph_TIM17, * RCC_APB2Periph_TIM9, RCC_APB2Periph_TIM10, RCC_APB2Periph_TIM11 * @param NewState: new state of the specified peripheral clock. * This parameter can be: ENABLE or DISABLE. * @retval None */ void RCC_APB2PeriphClockCmd(uint32_t RCC_APB2Periph, FunctionalState NewState) { /* Check the parameters */ assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph)); assert_param(IS_FUNCTIONAL_STATE(NewState)); if (NewState != DISABLE) { RCC->APB2ENR |= RCC_APB2Periph; } else { RCC->APB2ENR &= ~RCC_APB2Periph; } } /** * @brief Enables or disables the Low Speed APB (APB1) peripheral clock. * @param RCC_APB1Periph: specifies the APB1 peripheral to gates its clock. * This parameter can be any combination of the following values: * @arg RCC_APB1Periph_TIM2, RCC_APB1Periph_TIM3, RCC_APB1Periph_TIM4, * RCC_APB1Periph_TIM5, RCC_APB1Periph_TIM6, RCC_APB1Periph_TIM7, * RCC_APB1Periph_WWDG, RCC_APB1Periph_SPI2, RCC_APB1Periph_SPI3, * RCC_APB1Periph_USART2, RCC_APB1Periph_USART3, RCC_APB1Periph_USART4, * RCC_APB1Periph_USART5, RCC_APB1Periph_I2C1, RCC_APB1Periph_I2C2, * RCC_APB1Periph_USB, RCC_APB1Periph_CAN1, RCC_APB1Periph_BKP, * RCC_APB1Periph_PWR, RCC_APB1Periph_DAC, RCC_APB1Periph_CEC, * RCC_APB1Periph_TIM12, RCC_APB1Periph_TIM13, RCC_APB1Periph_TIM14 * @param NewState: new state of the specified peripheral clock. * This parameter can be: ENABLE or DISABLE. * @retval None */ void RCC_APB1PeriphClockCmd(uint32_t RCC_APB1Periph, FunctionalState NewState) { /* Check the parameters */ assert_param(IS_RCC_APB1_PERIPH(RCC_APB1Periph)); assert_param(IS_FUNCTIONAL_STATE(NewState)); if (NewState != DISABLE) { RCC->APB1ENR |= RCC_APB1Periph; } else { RCC->APB1ENR &= ~RCC_APB1Periph; } } #ifdef STM32F10X_CL /** * @brief Forces or releases AHB peripheral reset. * @note This function applies only to STM32 Connectivity line devices. * @param RCC_AHBPeriph: specifies the AHB peripheral to reset. * This parameter can be any combination of the following values: * @arg RCC_AHBPeriph_OTG_FS * @arg RCC_AHBPeriph_ETH_MAC * @param NewState: new state of the specified peripheral reset. * This parameter can be: ENABLE or DISABLE. * @retval None */ void RCC_AHBPeriphResetCmd(uint32_t RCC_AHBPeriph, FunctionalState NewState) { /* Check the parameters */ assert_param(IS_RCC_AHB_PERIPH_RESET(RCC_AHBPeriph)); assert_param(IS_FUNCTIONAL_STATE(NewState)); if (NewState != DISABLE) { RCC->AHBRSTR |= RCC_AHBPeriph; } else { RCC->AHBRSTR &= ~RCC_AHBPeriph; } } #endif /* STM32F10X_CL */ /** * @brief Forces or releases High Speed APB (APB2) peripheral reset. * @param RCC_APB2Periph: specifies the APB2 peripheral to reset. * This parameter can be any combination of the following values: * @arg RCC_APB2Periph_AFIO, RCC_APB2Periph_GPIOA, RCC_APB2Periph_GPIOB, * RCC_APB2Periph_GPIOC, RCC_APB2Periph_GPIOD, RCC_APB2Periph_GPIOE, * RCC_APB2Periph_GPIOF, RCC_APB2Periph_GPIOG, RCC_APB2Periph_ADC1, * RCC_APB2Periph_ADC2, RCC_APB2Periph_TIM1, RCC_APB2Periph_SPI1, * RCC_APB2Periph_TIM8, RCC_APB2Periph_USART1, RCC_APB2Periph_ADC3, * RCC_APB2Periph_TIM15, RCC_APB2Periph_TIM16, RCC_APB2Periph_TIM17, * RCC_APB2Periph_TIM9, RCC_APB2Periph_TIM10, RCC_APB2Periph_TIM11 * @param NewState: new state of the specified peripheral reset. * This parameter can be: ENABLE or DISABLE. * @retval None */ void RCC_APB2PeriphResetCmd(uint32_t RCC_APB2Periph, FunctionalState NewState) { /* Check the parameters */ assert_param(IS_RCC_APB2_PERIPH(RCC_APB2Periph)); assert_param(IS_FUNCTIONAL_STATE(NewState)); if (NewState != DISABLE) { RCC->APB2RSTR |= RCC_APB2Periph; } else { RCC->APB2RSTR &= ~RCC_APB2Periph; } } /** * @brief Forces or releases Low Speed APB (APB1) peripheral reset. * @param RCC_APB1Periph: specifies the APB1 peripheral to reset. * This parameter can be any combination of the following values: * @arg RCC_APB1Periph_TIM2, RCC_APB1Periph_TIM3, RCC_APB1Periph_TIM4, * RCC_APB1Periph_TIM5, RCC_APB1Periph_TIM6, RCC_APB1Periph_TIM7, * RCC_APB1Periph_WWDG, RCC_APB1Periph_SPI2, RCC_APB1Periph_SPI3, * RCC_APB1Periph_USART2, RCC_APB1Periph_USART3, RCC_APB1Periph_USART4, * RCC_APB1Periph_USART5, RCC_APB1Periph_I2C1, RCC_APB1Periph_I2C2, * RCC_APB1Periph_USB, RCC_APB1Periph_CAN1, RCC_APB1Periph_BKP, * RCC_APB1Periph_PWR, RCC_APB1Periph_DAC, RCC_APB1Periph_CEC, * RCC_APB1Periph_TIM12, RCC_APB1Periph_TIM13, RCC_APB1Periph_TIM14 * @param NewState: new state of the specified peripheral clock. * This parameter can be: ENABLE or DISABLE. * @retval None */ void RCC_APB1PeriphResetCmd(uint32_t RCC_APB1Periph, FunctionalState NewState) { /* Check the parameters */ assert_param(IS_RCC_APB1_PERIPH(RCC_APB1Periph)); assert_param(IS_FUNCTIONAL_STATE(NewState)); if (NewState != DISABLE) { RCC->APB1RSTR |= RCC_APB1Periph; } else { RCC->APB1RSTR &= ~RCC_APB1Periph; } }
接着,我们再看一下GPIO的库函数,我们打开GPIO.h的文件,然后拖到最后这些就是GPIO的全部库函数。我们目前需要了解的就是前面的这些函数,第一个就是GPIO_DeInit,参数可以写GPIOA、GPIOB等等,调用这个函数之后所指定的GPIO外设就会被复位,这就是这个函数的用途;第二个GPIO_AFIODeInit也是一样,可以复位AFIO外设;第三个GPIO_Init就是非常重要的函数,这个函数的作用是用结构体的参数来初始化GPIO口,我们需要先定义一个结构体变量,然后再给结构体赋值,最后调用这个函数,这个函数内部就会自动读取结构体的值,然后自动把外设的各个参数配置好,这种Init函数在STM32中基本所有的外设都有,一般我们初始化外设都是使用这个Init函数来完成的;第四个是GPIO_StructInit函数,这个函数可以把结构体变量赋一个默认值;这下面四个就是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的写入函数
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);
这些函数可以实现读写GPIO口的功能,最后剩下的这些函数我们暂时不会用到。
接下来使用这些函数来操作GPIO:
在main.c文件中,首先调用的是RCC里面的APB2外设时钟控制函数,复制粘贴。由于我们需要点亮的是PA0口的LED,所以选择RCC_APB2Periph_GPIOA作为第一个参数,并且选择ENABLE作为第二个参数,这样时钟就开启了。接着调用GPIO_Init函数,初始化,第一个参数选择GPIOA,第二个参数是一个结构体,首先复制结构体的类型GPIO_InitTypeDef
,并命名结构体为GPIO_InitStructure
,接着定义结构体的成员,由于点灯需要的是推挽输出,所以GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP;
,由于使用的是GPIOA的0号引脚,所以GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0;
,并且GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
,最后,将GPIO_InitStructure的地址作为第二个参数。
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);
第一个参数是选择外设,第二个参数是PortVal,这个函数可以同时对16个端口进行写入操作。
那我们分别来用一下试试,首先试一下ResetBits,LED灯亮,说明PA0口输出为低电平。
#include "stm32f10x.h" // Device header int main (void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); GPIO_ResetBits(GPIOA,GPIO_Pin_0); while(1) { } }
再试一下SetBits,将GPIO_ResetBits(GPIOA,GPIO_Pin_0);
改为GPIO_SetBits(GPIOA,GPIO_Pin_0);
,LED灯灭,说明PA0口输出为高电平。
再试一下void GPIO_WriteBit,使用GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);
,LED灯亮;使用GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);
,LED灯灭。
这就是这三个函数的用法。
接下来,我们来实现LED闪烁。我们需要再while循环函数中写上点亮LED,延时一段时间;熄灭LED,延时一段时间的代码。
使用下面的代码来实现点亮和熄灭LED:
GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET);//点亮LED
GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET);//熄灭LED
或
GPIO_ResetBits(GPIOA,GPIO_Pin_0);//点亮LED
GPIO_SetBits(GPIOA,GPIO_Pin_0);//熄灭LED
或
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0);
GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1);
在中间加上延时函数来进行延时,在工程文件夹中,新建文件夹System,将延时函数的.c和.h文件(使用SYSTICK延时器来实现的延时)粘贴进来,在keil中点击三个箱子的按钮,新建组System,添加延时函数的.c和.h文件,并点击魔术棒按钮,在C/C++中的include path选项中添加文件夹System的路径。
使用Delay_ms(500);
实现500ms的延时。
全部代码如下:
#include "stm32f10x.h" // Device header #include "Delay.h" int main(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA, &GPIO_InitStructure); while (1) { GPIO_ResetBits(GPIOA, GPIO_Pin_0); Delay_ms(500); GPIO_SetBits(GPIOA, GPIO_Pin_0); Delay_ms(500); GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_RESET); Delay_ms(500); GPIO_WriteBit(GPIOA, GPIO_Pin_0, Bit_SET); Delay_ms(500); GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)0); Delay_ms(500); GPIO_WriteBit(GPIOA, GPIO_Pin_0, (BitAction)1); Delay_ms(500); } }
最后我们再研究一下推挽输出和开漏输出的驱动问题,我们把这个LED拔掉,然后把长脚插到PA0口,短脚插到负极,这样LED就是高电平点亮的方式,可以看到LED也是正常闪烁,说明在推挽模式下高低电平都是有驱动能力的,那我们把这个端口的模式换成Out_OD,开漏输出模式,编译下载,可以看到LED就不亮了,现在LED还是高电平点亮的方式,LED不亮说明开漏输出的模式高电平是没有驱动的,我们把LED再改回低电平驱动的方式,可以看到LED又亮起来了,这说明开漏模式的低电平是有驱动能力的,这就是推挽输出和开漏输出的特性,推挽输出高低电平均有驱动能力,开漏输出高电平相当于高阻态,没有驱动能力,低电平有驱动能力,那我们把这个改回推挽输出,一般输出用推挽模式就行了,特殊的地方才会用到开漏模式。
可以使用GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;//初始化16个端口
初始化16个端口,也可以用GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2…;
进行初始化
#include "stm32f10x.h" // Device header #include "Delay.h" int main (void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_All;//初始化16个端口 GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOA,&GPIO_InitStructure); while(1) { GPIO_Write(GPIOA,~0x0001);//点亮LED 0000 0000 0000 0001 Delay_ms(500); GPIO_Write(GPIOA,~0x0002);//点亮LED 0000 0000 0000 0010 Delay_ms(500); GPIO_Write(GPIOA,~0x0004);//点亮LED 0000 0000 0000 0100 Delay_ms(500); GPIO_Write(GPIOA,~0x0008);//点亮LED 0000 0000 0000 1000 Delay_ms(500); GPIO_Write(GPIOA,~0x0010);//点亮LED 0000 0000 0001 0000 Delay_ms(500); GPIO_Write(GPIOA,~0x0020);//点亮LED 0000 0000 0010 0000 Delay_ms(500); GPIO_Write(GPIOA,~0x0040);//点亮LED 0000 0000 0100 0000 Delay_ms(500); GPIO_Write(GPIOA,~0x0080);//点亮LED 0000 0000 1000 0000 Delay_ms(500); } }
蜂鸣器连接到B12端口上
#include "stm32f10x.h" // Device header #include "Delay.h" int main (void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(GPIOB,&GPIO_InitStructure); while(1) { GPIO_ResetBits(GPIOB,GPIO_Pin_12); Delay_ms(100); GPIO_SetBits(GPIOB,GPIO_Pin_12); Delay_ms(100); GPIO_ResetBits(GPIOB,GPIO_Pin_12); Delay_ms(100); GPIO_SetBits(GPIOB,GPIO_Pin_12); Delay_ms(700); } }
那最后再给大家介绍几种使用库函数的方法,那第一种就是像我这样先打开点击.h文件的最后,看一下都有哪些函,数然后再右键转到定义查看一下函数和参数的用法,这里全都是英文的,如果看不懂的话借助一下翻译软件。第二种就是打开资料文件夹里的这个库函数用户手册,这里面有所有函数的介绍和使用方法,这个文档是中文的看起来比较好理解,而且这个函数下面都还给了例子,要用的话直接复制过来就行了,不过这个用户手册的版本并不对应我们现在用的这个库函数的版本,我们使用的库函数是V3.5.0版本的,这个用户手册是老版本,库函数的有部分用法会有些出入,但是整体上的差异都不大,参考这个用户手册也是没有问题的。V3.5.0的库函数目前还是没有用户手册的,St公司并没有发布,V3.5.0版本的库函数用户手册,而是在这个固件库压缩包中给了一个帮助文档,我们可以打开看一下可以找到GPIO这一节来看一下这种帮助文档,不过这个文档只有英文的版本。最后一种方式就是百度搜索参考一下别人的代码。
套件中提供了四种传感器模块,分别是光敏电阻传感器、热敏电阻传感器、对外式红外传感器、反射式红外传感器
上面的电路图是传感器的基本电路
按键的连接电路如下图所示,上面两个为下接按键的方式,下面两个为上接按键的方式,一般来说,按键都是使用下接的方式,是电路设计的习惯和规范。
那我们先来看一下第一个图,这种接法是按键的最常用的接法了,在这里随便选取一个GPIO口,比如PA0,然后通过K1接到地,当按键按下时,PA0被直接下达到GMT,此时读取PA0口的电压就是低电平,当按键松手时,PA0被悬空悬空,引脚的电压不确定,所以在这种解法下,必须要求PA0是上拉输入的模式,否则就会出现引脚电压不确定的错误现象,如果K0是上拉输入的模式,那引脚在悬空时就是高电平。所以这种方式下。按下按键。引脚为低电平。松手。引脚为高电平。
再看一下第二个图,相比较第一个图在这里外部接了一个上拉电阻,这个上拉电阻可以想象成一个弹簧把这个端口往屋顶上来,然后按键松手时,引脚由于上拉作用,自然保持为高电平,当按键按下时,引脚直接接到GND,也就是一股无穷大的力,把这个引脚往下拉,那弹簧肯定对抗不了无穷大的力,所以引脚就为低电平,这种状态下引脚不会出现悬空状态。所以此时PA0引脚可以配置为浮空输入或者上拉输入,如果是上拉输入,那就是内外两个上拉电阻共同作用,这时高电平就会更强一些,对应高电平就更加稳定,当然这样的话,当引脚被强行拉到低时,损耗也就会大一些。
那接着第三个图,PA0通过按键接到3.3V,这样也是可以的,不过要求PA0必须要配置成下拉输入的模式,当按键按下时,引脚为高电平,松手时,引脚回到默认值低电平,要求单片机的引脚可以配置为下拉输入的模式,一般单片机可能不一定有下拉输入的模式,所以最好还是用上面的方法,下面的作为扩展部分,了解一下即可。
那最后一种接法,就是在刚才的这种接法下面再外接一个下拉电阻,这个接法PA0需要配置为下拉输入模式或者浮空输入模式。
那总结一下就是上面这两种接法按键按下时,引脚是低电平,松手是高电平;下面这两种接法按键按下时,是高电平,松手,是低电平。左边两种接法必须要求引脚是上拉或者下拉输入的模式,右边两种接法可以允许引脚是浮空输入的模式,因为已经外置了上拉电阻和下拉电阻;一般我们都用上面两种接法,下面两种接法用的比较少。
传感器模块的连接电路如下图所示,
下面是C语言的知识的学习,就不再详细记录了,基本包括下面几个内容:
复制并粘贴之前的工程,更改名字,并在工程文件夹中新建文件夹Hardware,并在keil中进行相关设置。
实验现象:按下按键1,LED1亮,按下按键2,LED2亮,再按一下按键,LED灯灭。
右键点击Hardware组,添加新文件,新建LED.c文件,路径选择Hardware文件夹,点击Add;右键点击Hardware组,添加新文件,新建LED.h文件,路径选择Hardware文件夹,点击Add;分别编写LED.c和LED.h文件
#include "stm32f10x.h" // Device header void LED_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_2; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ; GPIO_Init(GPIOA ,&GPIO_InitStructure ); GPIO_SetBits (GPIOA ,GPIO_Pin_1 | GPIO_Pin_2); } void LED1_ON(void) { GPIO_ResetBits (GPIOA ,GPIO_Pin_1 ); } void LED1_OFF(void) { GPIO_SetBits (GPIOA ,GPIO_Pin_1 ); } void LED1_Turn(void) { if(GPIO_ReadOutputDataBit (GPIOA ,GPIO_Pin_1 )== 0) { GPIO_SetBits (GPIOA ,GPIO_Pin_1 ); } else { GPIO_ResetBits (GPIOA ,GPIO_Pin_1 ); } } void LED2_ON(void) { GPIO_ResetBits (GPIOA ,GPIO_Pin_2 ); } void LED2_OFF(void) { GPIO_SetBits (GPIOA ,GPIO_Pin_2 ); } void LED2_Turn(void) { if(GPIO_ReadOutputDataBit (GPIOA ,GPIO_Pin_2 )== 0) { GPIO_SetBits (GPIOA ,GPIO_Pin_2 ); } else { GPIO_ResetBits (GPIOA ,GPIO_Pin_2 ); } }
#ifndef __LED_H
//是否存在LED.H的字符串
#define __LED_H
//若不存在,定义LED.H的字符串
void LED_Init(void);
void LED1_ON(void);
void LED1_OFF(void);
void LED1_Turn(void);
void LED2_ON(void);
void LED2_OFF(void);
void LED2_Turn(void);
#endif
右键点击Hardware组,添加新文件,新建Key.c文件,路径选择Hardware文件夹,点击Add;右键点击Hardware组,添加新文件,新建Key.h文件,路径选择Hardware文件夹,点击Add;分别编写Key.c和Key.h文件
#include "stm32f10x.h" // Device header #include "Delay.h" void Key_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ,ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1 | GPIO_Pin_11; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ; GPIO_Init(GPIOB ,&GPIO_InitStructure ); } uint8_t Key_GetNum(void ) { uint8_t KeyNum = 0; if(GPIO_ReadInputDataBit (GPIOB ,GPIO_Pin_1 ) == 0) { Delay_ms(20); while (GPIO_ReadInputDataBit (GPIOB ,GPIO_Pin_1 ) ==0 ); Delay_ms (20); KeyNum = 1; } if(GPIO_ReadInputDataBit (GPIOB ,GPIO_Pin_11 ) == 0) { Delay_ms(20); while (GPIO_ReadInputDataBit (GPIOB ,GPIO_Pin_11 ) ==0 ); Delay_ms (20); KeyNum = 2; } return KeyNum ; }
#ifndef __KEY_H
#define __KEY_H
void Key_Init(void);
uint8_t Key_GetNum(void );
#endif
#include "stm32f10x.h" // Device header #include "Delay.h" #include "LED.h" #include "Key.h" uint8_t KeyNum; int main (void) { LED_Init(); Key_Init(); while(1) { KeyNum = Key_GetNum() ; if(KeyNum == 1) { LED1_Turn (); } if(KeyNum == 2) { LED2_Turn (); } } }
实验现象:遮住光敏电阻,蜂鸣器响,不遮挡光敏电阻,蜂鸣器不响。
右键点击Hardware组,添加新文件,新建Buzzer.c文件,路径选择Hardware文件夹,点击Add;右键点击Hardware组,添加新文件,新建Buzzer.h文件,路径选择Hardware文件夹,点击Add;分别编写Buzzer.c和Buzzer.h文件
#include "stm32f10x.h" // Device header #include "stm32f10x.h" // Device header void Buzzer_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP ; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_12; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ; GPIO_Init(GPIOB ,&GPIO_InitStructure ); GPIO_SetBits (GPIOB ,GPIO_Pin_12); } void Buzzer_ON(void) { GPIO_ResetBits (GPIOB ,GPIO_Pin_12 ); } void Buzzer_OFF(void) { GPIO_SetBits (GPIOB ,GPIO_Pin_12 ); } void Buzzer_Turn(void) { if(GPIO_ReadOutputDataBit (GPIOB ,GPIO_Pin_12 )== 0) { GPIO_SetBits (GPIOB ,GPIO_Pin_12 ); } else { GPIO_ResetBits (GPIOB ,GPIO_Pin_12 ); } }
#ifndef __BUZZER_H
#define __BUZZER_H
void Buzzer_Init(void);
void Buzzer_ON(void);
void Buzzer_OFF(void);
void Buzzer_Turn(void);
#endif
右键点击Hardware组,添加新文件,新建LightSensor.c文件,路径选择Hardware文件夹,点击Add;右键点击Hardware组,添加新文件,新建LightSensor.h文件,路径选择Hardware文件夹,点击Add;分别编写LightSensor.c和LightSensor.h文件
#include "stm32f10x.h" // Device header void LightSensor_Init(void) { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB ,ENABLE); GPIO_InitTypeDef GPIO_InitStructure; GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU ; GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13; GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz ; GPIO_Init(GPIOB ,&GPIO_InitStructure ); } uint8_t LightSensor_Get(void) { return GPIO_ReadInputDataBit (GPIOB ,GPIO_Pin_13); }
#ifndef __LIGHTSENSOR_H
#define __LIGHTSENSOR_H
void LightSensor_Init(void);
uint8_t LightSensor_Get(void);
#endif
#include "stm32f10x.h" // Device header #include "Delay.h" #include "Buzzer.h" #include "LightSensor.h" uint8_t KeyNum; int main (void) { Buzzer_Init (); LightSensor_Init (); while(1) { if(LightSensor_Get() == 1) { Buzzer_ON(); } else { Buzzer_OFF(); } } }
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。