用8G1K08A的按键和PWM练习
几个月前开始接触STC8G1K08A这8脚单片机,觉得挺有意思的,范例代码要做成实用的功能,还是要很多试验,才能有一些收获。先实现了上电等待5秒,再接通1秒,然后断开进入掉电模式,仅涉及定时器和IO相关的代码
再实现了桶装水自动抽水器的定时功能,短按开始抽水,再短按,停止抽水,或者自动倒计时 n 秒后停止抽水;长按3秒开始抽水并进入设置模式,直到短按停止抽水,自动保存长按开始到短按结束之间的时间,作为下次自动倒计时时长,即倒计时时长可设置。涉及定时器、IO、按键中断,短按,长按,长长按,EEPROM读写等操作,还有就是掉电模式进入和恢复等。
最近又研究PWM,控制LED高亮、中亮、低亮、熄灭的不同显示效果,用deepseek和kimi提供的代码,由于不是适配STC8G1K08A芯片,所以无法运行,看STC8G.pdf芯片规范文件,还是很多不理解,特别是IO口不同工作模式的切换,希望大佬可以指点指点。
以下是使用STC8G1K08A单片机实现通过按键控制LED开关和亮度的代码示例。代码基于STC单片机的C语言开发环境,使用PWM信号控制LED亮度,并通过按键切换高亮、中亮、低亮和熄灭状态。
硬件连接说明
[*]P32:按键输入,连接到单片机的P32引脚。
[*]P54:PWM输出,连接到单片机的P54引脚,用于控制LED亮度,默认输出高电平(熄灭)。
[*]LED:通过电阻连接到P54引脚,另一端接电源正极,当IO口低电平时点亮。
[*]按键:一端连接到P32引脚,另一端接地。
软件设计思路
[*]PWM控制:使用STC单片机的定时器功能生成PWM信号,通过占空比控制LED亮度。
[*]按键检测:检测P32引脚的状态,判断按键是否按下。
[*]状态切换:通过按键切换LED的亮度状态(高亮、中亮、低亮、熄灭)。
[*]上电默认高亮:程序启动时,设置为高亮状态。
#include "STC8G.H"
#define MAIN_Fosc 24000000L // 定义主时钟
#define MCU_IDLE() PCON |= 1 /* MCU 进入 IDLE 模式 */
#define MCU_POWER_DOWN() PCON |= 2 /* MCU 进入 睡眠 模式 */
#define u1 bit
#define u8 unsigned char
#define u16 unsigned int
#define u32 unsigned long
#define IDLE_TIME 3000000L // 空闲计数器阈值
// 定义按键引脚
#define KEY_PIN P32// 按键连接P32
// 定义亮度档位
// 定义PWM相关参数
#define PWM_HIGH_DUTY 0xFF // 高亮占空比(高电平时间长) = 常亮
#define PWM_MEDIUM_DUTY 0x80 // 中亮占空比
#define PWM_LOW_DUTY 0x40 // 低亮占空比
#define PWM_OFF_DUTY 0x00 // 熄灭占空比(低电平)
extern void _nop_ (void);
// 定义状态变量
u8 led_state = 0; // LED状态:0-高亮,1-中亮,2-低亮,3-熄灭
u1 wakeup_status = 1; // 运行标志(0:休眠,1:活跃)
u32 idle_time = 0; // 空闲计数器
// 延时函数, ms,要延时的ms数, 这里只支持1~255ms. 自动适应主时钟.
void delay_ms(unsigned int ms)
{
unsigned int i;
do{
i = MAIN_Fosc / 10000;
while(--i);
}while(--ms);
}
// 初始化PWM
void PWM_Init() {
// 配置 PCA
CCON= 0x00;
CL = 0x00;
CH = 0x00;
CCAPM2 = 0x42; // PCA 模块2为PWM工作模式
CR = 1; // 启动PCA 计数器
}
// 设置PWM占空比,输出8位的PWM
void Set_PWM_Duty(u8 duty) {
if (duty == 0xFF){ // 固定输出低电平,常亮
PCA_PWM2 &= 0x3F;
CCAP2H = 0xFF;
}else if (duty == 0x00){ // 固定输出高电平,熄灭
PCA_PWM2 &= 0xC0;
CCAP2H = 0x00;
}else{ // 输出8位的PWM
PCA_PWM2 &=0x00;
CCAP2L = duty; // 设置占空比(低字节)
CCAP2H = duty; // 设置占空比(高字节)
}
}
// 按键检测
u8 Key_Scan() {
if (KEY_PIN == 0) {// 检测按键是否按下
delay_ms(20);// 消抖
if (KEY_PIN == 0) {
while (KEY_PIN == 0);// 等待按键释放
return 1;// 返回按键按下标志
}
}
return 0;// 无按键按下
}
// 初始化I/O端口
void InitPorts()
{
// 初始化为准双向
P3M0 = 0x00; P3M1 = 0x00;
P5M0 = 0x00; P5M1 = 0x00;
}
// 外部中断0初始化
void Int0_Init(void) {
IT0 = 1; // 使能INT0下降沿中断
EX0 = 1; // 使能INT0中断0
EA = 1; // 使能中断总开关
}
// 掉电模式
void PowerDownMode(void) {
wakeup_status = 0;
_nop_();
_nop_();
MCU_POWER_DOWN();// MCU进入掉电模式(STC8G系列)
_nop_();
_nop_();
_nop_();
_nop_();
}
// 从掉电模式唤醒
void WakeUpFromPowerDown(void) {
PCON &= 0xFD; // 清除掉电标志
}
// 外部中断0服务程序(按键唤醒)
void INT0_ISR(void) interrupt 0 {
if (!wakeup_status){ // 如果在休眠状态,就执行唤醒操作
wakeup_status = 1;
WakeUpFromPowerDown(); // 从掉电模式唤醒
}
}
// 主函数
void main() {
InitPorts(); // 初始化端口
Int0_Init(); // 初始化外部中断0
PWM_Init();// 初始化PWM
// 上电默认高亮
Set_PWM_Duty(PWM_HIGH_DUTY);
led_state = 0;
while (1) {
idle_time++;
if (Key_Scan()) {// 检测按键
led_state++;// 切换LED状态
idle_time = 0; //重置空闲计数器
if (led_state > 3) {
led_state = 0;// 循环回到高亮状态
}
// 根据状态设置PWM占空比或普通输出高电平
switch (led_state) {
case 0:// 高亮
Set_PWM_Duty(PWM_HIGH_DUTY);
break;
case 1:// 中亮
Set_PWM_Duty(PWM_MEDIUM_DUTY);
break;
case 2:// 低亮
Set_PWM_Duty(PWM_LOW_DUTY);
break;
case 3:// 熄灭
Set_PWM_Duty(PWM_OFF_DUTY);
break;
}
}else{
if (led_state == 3 && idle_time >= IDLE_TIME){ // 熄灭时,进入掉电省电模式
PowerDownMode();
}
}
}
}
CCAPnL
CCAPnH 这两个寄存器是干啥用的,看数据手册写的我没有完全理解,可能是我的理解能力有问题。能否给讲解一下谢谢!
阿白凌坤 发表于 2025-4-18 11:22
CCAPnL
CCAPnH 这两个寄存器是干啥用的,看数据手册写的我没有完全理解,可能是我的理解能力有问题。能 ...
理论上这是内部使用的,我们只要设置好CL和CH初始值,然后修改对应PWM,
CCAPnL中的n是指第几个PWM,例如代码中使用模块2,所以后续代码就设置CCAP2L和CCAP2H
页:
[1]