项目案例:按键控制灯光的开关切换
硬件电路:详见:XMF06A电路结构框图。
功能要求:
步骤1:系统上电后,D3灯到D6灯依次点亮,然后依次熄灭,进行灯光检测。
步骤2:查询按键SW3的状态,如果SW3按下,等待按键松开后,切换D3灯的开关状态。
步骤3:重复步骤2。
STM8关于GPIO的知识要点
STM8S106K6芯片共有32个引脚,其中GPIO有25个,但实际上可以供开发使用的只有22个。因为PA1和PA2需要用于外部晶振,PD1需要用与仿真器的数据接口。
STM8的GPIO有如下的主要功能特性:
1. 端口的各个位可以被单独配置。
2. 可选择的输入模式:浮动输入、带上拉输入。
3. 可选择的输出模式:推挽式输出、开漏输出。
4. 数据输入和输出采用独立的寄存器。
5. 外部中断可以单独使能和关闭。
6. 片上外设的I/O功能复用。
7. 输出摆率控制用以减少EMC噪声。
8. 当作为模拟输入时,可以关闭输入施密特触发器来降低功耗。
9. 在数据输出锁存时,支持“读-修改-写”。
10. 输入兼容5V电压。
11. I/O端口的工作电压范围是1.6V到VDDIOmax。
每一个端口有5个相关的寄存器,每个寄存器都可以位操作:
数据输出寄存器 Px_ODR。
引脚输入寄存器 Px_IDR。
数据方向寄存器 Px_DDR。
控制寄存器1 Px_CR1。
控制寄存器2 Px_CR2。
寄存器的具体定义详见:【STM8开发速查】GPIO常用寄存器定义与应用参考。
一个I/O端口工作在输入还是输出模式,取决于该端口的数据方向寄存器的状态。
输入模式:将DDRx位清0就选择了输入模式。
在该模式下,读Px_IDR寄存器的位将返回对应I/O引脚上的电平值。
输出模式:将DDRx位置1就选择了输出模式。
在该模式下,向Px_ODR寄存器的位写入数据将会通过锁存器输出对应的数字值到I/O端口。
项目案例的基本实现思路
为了编程方便,首先对LED灯和按键对应的引脚作宏定义的预处理。在这里需要注意的是,写GPIO和读GPIO是两个不同的寄存器。这两个寄存器都可以位操作,在头文件iostm8s105k6.h中对寄存器的位做了命名,我们可以直接利用这些名字操作寄存器对应的位。例如:PC2的输出位就是PC_ODR_ODR2,PB0引脚的输入位为PB_IDR_IDR0。
在对具体引脚操作之前,需要对其进行初始化。首先对数据方向寄存器Px_DDR进行设置,确定了引脚输入或输出之后,再根据应用需要对Px_CR1和Px_CR2进行设置。对GPIO进行了正确的初始化后,就可以根据项目案例的要求进行相应的逻辑编码了。
案例的参考源码及注释
#include "iostm8s105k6.h"
#define D3 PC_ODR_ODR1
#define D4 PC_ODR_ODR2
#define D5 PC_ODR_ODR3
#define D6 PC_ODR_ODR4
#define SW3 PB_IDR_IDR0
/*=========================普通延时函数==========================*/
void Delay(unsigned int t)
{
while(t--);
}
/*=========================灯光测试函数==========================*/
void LED_Check()
{
//D3灯到D6灯依次点亮
D3 = 1; //D3灯点亮
Delay(60000);
D4 = 1; //D4灯点亮
Delay(60000);
D5 = 1; //D5灯点亮
Delay(60000);
D6 = 1; //D6灯点亮
Delay(60000);
//D3灯到D6灯依次熄灭
D3 = 0; //D3灯熄灭
Delay(60000);
D4 = 0; //D4灯熄灭
Delay(60000);
D5 = 0; //D5灯熄灭
Delay(60000);
D6 = 0; //D6灯熄灭
Delay(60000);
}
/*========================GPIO端口初始化=========================*/
void Init_GPIO()
{
//初始化按键SW3的PB0引脚
PB_DDR &= ~0x01; //PB0设置为输入模式
PB_CR1|= 0x01; //PB0设置为带上拉电阻输入
PB_CR2&= ~0x01; //PB0禁止外部中断
//初始化D3灯的PC1引脚
PC_DDR |= 0x1e; //PC1、PC2、PC3、PC4设置为输出模式
PC_CR1|= 0x1e; //PC1、PC2、PC3、PC4设置为推挽输出
PC_CR2&= ~0x1e; //PC1、PC2、PC3、PC4输出速度最大为2MHz
}
/*===========================按键扫描函数========================*/
void Scan_Keys()
{
if(SW3 == 0) //监测SW3的输入信号
{
Delay(100); //按键去抖动处理
if(SW3 == 0) //确认为SW3按键触发信号
{
while(SW3 == 0); //等待按键松开
D3 = ~D3; //切换D3灯的开关状态
}
}
}
/*==========================主函数===============================*/
void main()
{
Init_GPIO(); //初始化GPIO端口
LED_Check(); //依次检测灯光
while(1)
{
Scan_Keys(); //轮询扫描按键
}
}