本次程序设计和仿真是基于Proteus和keil的环境对STM32F103系列单片机进行流水灯设计,通过配置STM32的GPIO工作模式,实现LED的点亮和熄灭;通过配置8位流水灯程序设计,实现灯的流水实现。
关键字:Proteus、keil、STM32F103、GPIO
用STM32一个端口接8个发光二极管,编写程序,实现从左到右轮流点亮8个二极管(即流水灯)
仿真采用Proteus 8.9 SP2安装链接
第一步:在Proteus中的[P]选择所需要的零件有电阻RES、LED灯LED-GREEN最后还有单片机STM32F103R6
第二步:放置STM32F103R6单片机并设置VDDA、VSSA管脚以及NRST、VBAT和BOOT0
Design->Configure Power Rails ->Power Rails
第三步:放置八个LED
为什么LED接1K的电阻,这个可以参考链接2.2.2
GPIO总体分为7个部分:
- 保护二极管及上、下拉电阻:保护二级管可以防止引脚外部过高或过低的电压输入
- P-MOS 管和N-MOS 管:控制推挽输出和开漏输出
- 输出数据寄存器:由输出数据寄存器GPIOX_ODR
- 复用功能输出:STM32 的其它片上外设对GPIO 引脚进行控制
- 输入数据寄存器:存储输入数据寄存器GPIOx_IDR
- 复用功能输入:GPIO 引脚的信号传输到STM32 其它片上外设
- 模拟输入输出:用于ADC 采集电压的输入通道
GPIO 总共有8 种细分的工作模式
typedef enum
{
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 // 复用推挽输出
} GPIOMode_TypeDef;
稍加整理可以大致归类为以下三类:
在输入模式时,施密特触发器打开,输出被禁止,可通过输入数据寄存器GPIOx_IDR
读取I/O 状态。其中输入模式,可设置为上拉、下拉、浮空和模拟输入四种。上拉和下拉
输入很好理解,默认的电平由上拉或者下拉决定。浮空输入的电平是不确定的,完全由外
部的输入决定,一般接按键的时候用的是这个模式。模拟输入则用于ADC 采集。
在输出模式中,推挽模式时双MOS 管以轮流方式工作,输出数据寄存器GPIOx_ODR
可控制I/O 输出高低电平。开漏模式时,只有N-MOS 管工作,输出数据寄存器可控制I/O
输出高阻态或低电平。输出速度可配置,有2MHz\10MHz\50MHz 的选项。此处的输出速
度即I/O 支持的高低电平状态最高切换频率,支持的频率越高,功耗越大,如果功耗要求
不严格,把速度设置成最大即可。
在输出模式时施密特触发器是打开的,即输入可用,通过输入数据寄存器GPIOx_IDR
可读取I/O 的实际状态。
复用功能模式中,输出使能,输出速度可配置,可工作在开漏及推挽模式,但是输出
信号源于其它外设,输出数据寄存器GPIOx_ODR 无效;输入可用,通过输入数据寄存器
可获取I/O 实际状态,但一般直接用外设的寄存器来获取该数据信号。
通过对GPIO 寄存器写入不同的参数,就可以改变GPIO 的工作模式,再强调一下,
要了解具体寄存器时一定要查阅《STM32F10X-中文参考手册》中对应外设的寄存器说明。
在GPIO 外设中,控制端口高低控制寄存器CRH 和CRL 可以配置每个GPIO 的工作模式和
工作的速度,每4 个位控制一个IO,CRH 控制端口的高八位,CRL 控制端口的低8 位,
具体的看CRH 和CRL 的寄存器描述。
程序设计采用MDK 5.22安装链接
/******************************************************************************
* @brief Water_LED:流水灯实现
******************************************************************************/
void Water_LED(void)
{
unsigned long int time = 0xFFFF; //设置软件延时时间
unsigned char Count = 0x00; //设置流水起始地址
unsigned char Stars = 0xFE; //设置流水灯初始状态
unsigned char Move = 0x01; //设置移动补偿
while((!((Count++)&0x08))) //循环实现8位流水灯
{
GPIOC->ODR = Stars; //改变输出寄存器,改变端口状态
while(time--); //软件延时高电平持续实现
time = 0xFFFF;
GPIOC->ODR = 0xFF; //消抖实现
Stars = (Stars<<1)|(Move); //补偿实现
// Stars = 0xFE (1111 1110B)左移一位为(1111 1100B)为了补偿最后一个0
//Stars| Move =(1111 1100B)| 0000 0001B)=(1111 1101B)
Move = Move*2; //Move = (0000 0010B)
Move ++ ; //Move = (0000 0011B)
while(time--); //软件延时低电平持续时间
time = 0xFFFF;
}
}
/******************************************************************************
* @brief Water_GPIO_Init:流水灯GPIO口初始化
******************************************************************************/
void Water_GPIO_Init(void)
{
GPIO_InitTypeDef GPIO_OUT_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);//使能GPIO口时钟
GPIO_OUT_InitStructure.GPIO_Pin=GPIO_Pin_0|GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_3|GPIO_Pin_4|GPIO_Pin_5|GPIO_Pin_6|GPIO_Pin_7;
//选择指定管脚
GPIO_OUT_InitStructure.GPIO_Mode=GPIO_Mode_Out_OD; //设置开漏输出
GPIO_OUT_InitStructure.GPIO_Speed=GPIO_Speed_2MHz; //设置输出频率
GPIO_Init(GPIOC,&GPIO_OUT_InitStructure);
GPIOC->ODR = 0xFF; //初始化后LED全熄灭
}
int main(void)
{
SysClock_Configuration(RCC_PLLSource_HSI_Div2,RCC_CFGR_PLLMULL3);//设置系统时钟
Water_GPIO_Init(); //流水灯GPIO口初始化
while(1)
Water_LED(); //流水灯实现
}
1、流水程序设计是没有考虑GPIO8~15的状态,所以GPIOC高位以上的管脚要是用到其他功能,,可能会出问题