)
3.2 GPIO输出实战本节会用到RCC和GPIO两个功能3.2.1 RCC库函数寻找库函数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);代码来源于keil中库函数的声明RCC常用的三个库函数如上AHB外设时钟控制函数第一个使能或者失能AHB外设时钟第一个参数为选择哪一个外设STM互联型的设备在下面的arg中可以进行选择其他设备在下面选择。第二个参数为enable和disable也就是开启或者关闭APB1和ABP2是一样的参数如果不清楚哪个外设是连接在连接在哪个总线上还可以通过列表进行查找。3.2.2 GPIO库函数void GPIO_DeInit(GPIO_TypeDef* GPIOx); void GPIO_AFIODeInit(void); void GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_InitTypeDef* GPIO_InitStruct); void GPIO_StructInit(GPIO_InitTypeDef* GPIO_InitStruct); 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); 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); void GPIO_PinLockConfig(GPIO_TypeDef* GPIOx, uint16_t GPIO_Pin); void GPIO_EventOutputConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource); void GPIO_EventOutputCmd(FunctionalState NewState); void GPIO_PinRemapConfig(uint32_t GPIO_Remap, FunctionalState NewState); void GPIO_EXTILineConfig(uint8_t GPIO_PortSource, uint8_t GPIO_PinSource); void GPIO_ETH_MediaInterfaceConfig(uint32_t GPIO_ETH_MediaInterface);代码来源于keil中库函数的声明GPIO_DeInit用于复位指定的GPIO调户函数之后指定的GPIO会被复位void GPIO_AFIODeInit可以复位AFIO外设void GPIO_Init用结构体的参数来初始化GPIO口需要先定义一个结构体变量然后再给结构体赋值赋的值是比如IO口是输入还是输出推挽还是开漏最后调用这个函数这个函数内部会自动读取结构体的值然后自动把外设的各个参数配置好。这种Init函数在STM31中基本所有的外设都有void GPIO_StructInit把结构体变量赋一个默认值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的读写功能3.2.3 点亮小灯接线图1、激活时钟选择RCC_APB2Periph_GPIOA原因AHB是用于激活高速核心外设例如flash存储器cortex内核GPIO是高速外设因此挂在ABP2上因为LED硬件接在PA0口因此选择GPIOA文章GPIO介绍也提到过2、初始化GPIO此时需要定义结构体但是库函数已经帮我找好了三个参数Mode、Pin和Speed具体代码见下方完整代码Mode单机main函数中的Mode跳转选中Mode_DefinectrlF搜索最终跳转页面如上图此处是GPIO的八种工作模式AIN模拟输入IN_浮空输入IPD下拉输入IPU上拉输入Out_OD开漏输出AF复用Out_PP推挽输出AF复用此处点亮小灯使用推挽输出选择Out_PP这一项Pin选择引脚右键跳转后Pin有多个选项此处选择member选项然后同上Mode选择即可此处选择P0Speed处选择50MHz即可此处初始化第二个参数完成注意第二个参数需要加取地址符3、使用四个写入函数void GPIO_SetBits把指定端口设置为高电平void GPIO_ResetBits把指定端口设置为低电平以上两个函数的参数都是用于寻找端口void GPIO_WriteBit根据第三个参数的值来设置指定的端口void GPIO_Write第二个参数可以同时对十六个端口进行写入因为单片机一般使用低电平驱动因此使用WriteByte函数时需要设为RESET此时就已经完成了LED点亮的功能代码如下#include stm32f10x.h // Device header int main() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Pin GPIO_Pin_0; GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA,GPIO_InitStruct); GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET); while(1) { } }3.2.4 LED小灯闪烁小灯闪烁为了实现闪烁就需要在主函数中实现点亮-延时-点亮-延时首先需要实现Delay的功能在工程文件夹下新建一个文件夹-System将Delay文件放入其中然后在keil中File管理三个小方块按键中将System中的Delay文件加入进去然后再魔术棒-C/C中添加头文件路径-System即可使用Delay之前需要再main.c中添加#include Delay.h然后直接使用Delay.h中的函数就行LED小灯闪烁代码如下#include stm32f10x.h // Device header #include Delay.h int main() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Pin GPIO_Pin_0; GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA,GPIO_InitStruct); GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET); while(1) { GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET); Delay_ms(500); GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_SET); Delay_ms(500); } }此时如果将LED反过来就是高电平驱动模式说明在推挽模式下高低电平都是有驱动能力的但是如果将推挽输出改成开漏输出在高电平驱动模式下的LED小灯是不亮的说明开漏输出的模式高电平是没有驱动能力的3.2.5 LED流水灯接线图如图所示直接复制LED闪烁的代码即可省去了初始化文件的时间变化如下1、将GPIO结构体参数中的Pin参数增加至7代码中直接使用all即可中间用或|连接即可因为函数定义汇总十六个引脚是通过八进制数字来进行初始化的每一位对应一个引脚因此还可以使用函数中all这个参数来一次性初始化所有引脚2、因此输出的函数也要修改为最后加“S”3、在给输出的时候直接使用GPIO_Write这个函数即可同时对十六个引脚进行赋值详情见3.2.2但是编译器不支持直接写二进制数因此需要转为八进制进行书写详情代码如下#include stm32f10x.h // Device header #include Delay.h int main() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Pin GPIO_Pin_All; GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA,GPIO_InitStruct); GPIO_WriteBit(GPIOA,GPIO_Pin_0,Bit_RESET); while(1) { GPIO_Write(GPIOA,~0x0001);//0000 0000 0000 0001 Delay_ms(500); GPIO_Write(GPIOA,~0x0002);//0000 0000 0000 0010 Delay_ms(500); GPIO_Write(GPIOA,~0x0004);//0000 0000 0000 0100 Delay_ms(500); GPIO_Write(GPIOA,~0x0008);//0000 0000 0000 1000 Delay_ms(500); GPIO_Write(GPIOA,~0x0010);//0000 0000 0001 0000 Delay_ms(500); GPIO_Write(GPIOA,~0x0020);//0000 0000 0010 0000 Delay_ms(500); GPIO_Write(GPIOA,~0x0040);//0000 0000 0100 0000 Delay_ms(500); GPIO_Write(GPIOA,~0x0080);//0000 0000 1000 0000 Delay_ms(500); } }3.2.6 蜂鸣器接线图在选择端口的时候需要避开A15、B3和B4这三个端口是调试端口如果想要让其作为正常的IO口使用的话需要进行单独配置。设备说明是低电平触发蜂鸣器因此给IO口低电平就会响具体代码如下#include stm32f10x.h // Device header #include Delay.h int main() { RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE); GPIO_InitTypeDef GPIO_InitStruct; GPIO_InitStruct.GPIO_Mode GPIO_Mode_Out_PP; GPIO_InitStruct.GPIO_Pin GPIO_Pin_12; GPIO_InitStruct.GPIO_Speed GPIO_Speed_50MHz; GPIO_Init(GPIOA,GPIO_InitStruct); while(1) { GPIO_WriteBit(GPIOA,GPIO_Pin_12,Bit_RESET); Delay_ms(500); GPIO_WriteBit(GPIOA,GPIO_Pin_12,Bit_SET); Delay_ms(500); } }