实例介绍
这段代码实现了基于 NY8BE62D 微控制器的 RGB LED 三键独立调光系统,核心功能如下:
一、硬件资源映射
| 引脚 | 功能 | 外设 |
|---|---|---|
| PA4 | 红色LED | PWM2 |
| PA7 | 绿色LED | PWM3 |
| PB1 | 蓝色LED | PWM1 |
| PA6/PA0/PA1 | 红/绿/蓝按键 | 内部上拉输入 |
二、主要功能特点
1. 独立三通道控制
- 三个按键分别控制红、绿、蓝LED亮度
- 每通道支持 8级亮度(0~7循环)
- 亮度值通过 brightness_R/G/B 变量保存
2. 硬件PWM实现
- 使用芯片内置的 PWM1/PWM2/PWM3 模块
- PWM分辨率 10位(0~1023)
- 支持动态频率调节(20Hz ~ 10kHz)
3. 按键扫描机制
- 采用状态机实现按键消抖与长按检测
- 短按:切换亮度等级(0→1→…→7→0)
- 内置延时判断,避免重复触发
4. 定时系统
- Timer0 产生100μs中断
- 每10次中断(1ms)触发一次按键扫描
- 同时提供1ms/10ms/100ms软件定时标志
三、核心函数说明
| 函数 | 作用 |
|---|---|
| PWM_Init() | 初始化三路PWM,默认1kHz频率 |
| PWM_SetFrequency() | 动态修改PWM频率(全局生效) |
| PWM_UpdateDuty_*() | 将亮度等级转换为占空比(0~1023) |
| KeyScan_*() | 各按键独立扫描与亮度更新 |
| TIMR0_Init() | 配置100μs定时中断 |
四、亮点设计
- 频率独立可调:修改 pwm_freq_hz 变量并调用 PWM_SetFrequency() 即可
- 看门狗保护:主循环中定期喂狗,增强系统稳定性
- 低功耗预留:WakeUpFlag 变量为休眠唤醒预留接口
- 代码模块化:红绿蓝三通道逻辑独立,便于维护
五、使用方式
- 上电后所有LED熄灭(亮度0)
- 按下某颜色按键 → 该通道亮度 1(循环0-7)
- 如需改变PWM频率,在main中调用 PWM_SetFrequency(5000) 即可
这是一个典型的嵌入式多任务状态机设计,充分利用了MCU硬件PWM资源,避免了软件模拟PWM对CPU的占用。
/*===========================================================================*/
// 文件名: main.c// 芯片型号: NY8BE62D (SOP16)
// 功能描述: 三按键独立控制 RGB LED 亮度 (硬件PWM, 8级亮度, 频率可调 20Hz~10kHz)
// 引脚映射:
// PWM2(PA4) -> 红色LED
// PWM3(PA7) -> 绿色LED
// PWM1(PB1) -> 蓝色LED
// 按键R(PA6), 按键G(PA0), 按键B(PA1) (内部上拉, 低电平有效)
// 频率设置: 修改全局变量 pwm_freq_hz 后调用 PWM_SetFrequency() 即可
// 编译环境: Nyquest NYC 编译器 / SDCC (包含 ny8be62d.h 和 ny8common.h)
//===========================================================================*/
#include <ny8be62d.h>
#include <ny8common.h>
// 数据类型
#define u8 unsigned char
#define u16 unsigned int
#define u32 unsigned long
// 硬件引脚映射
#define LED_R PA4 // 红色LED -> PWM2
#define LED_G PA7 // 绿色LED -> PWM3
#define LED_B PB1 // 蓝色LED -> PWM1
#define KEY_R PA6
#define KEY_G PA0
#define KEY_B PA1
// PWM 参数
#define PWM_RESOLUTION 1024
#define BRIGHTNESS_LEVELS 8
#define INSTRUCTION_FREQ 1000000UL // 1MHz (16MHz/4T)
#define MIN_PWM_FREQ 20
#define MAX_PWM_FREQ 10000
// T0MD 寄存器配置值 (PS0WDT=0 给 Timer0, PS0SEL=2 对应 1:4 分频)
#define T0MD_CONFIG 0x02
// PCON1 寄存器位掩码
#define PCON1_TOEN 0x01 // bit0: Timer0 使能
// Timer1/PWM 控制位
#define T1EN 0x80
#define T1RL 0x40
#define PWM1OE 0x20
#define T1PS_1 0x00
#define PWMxEN 0x80
#define PWMxS_TMR1 0x00
// 全局变量
unsigned char key0;
__sbit delay_1ms_fig = key0:0;
__sbit delay_10ms_fig = key0:1;
__sbit delay_100ms_fig = key0:2;
unsigned char key1;
__sbit KeySubStep_R = key1:0;
__sbit KeySubStep_G = key1:1;
__sbit KeySubStep_B = key1:2;
__sbit WakeUpFlag = key1:3;
volatile u8 brightness_R = 0;
volatile u8 brightness_G = 0;
volatile u8 brightness_B = 0;
volatile u16 pwm_freq_hz = 1000;
u16 keyDelay_R = 0, keyDelayTimr_R = 0;
u16 keyDelay_G = 0, keyDelayTimr_G = 0;
u16 keyDelay_B = 0, keyDelayTimr_B = 0;
u8 tmr0_100us_cnt = 0;
// 函数声明
void TIMR0_Init(void);
void PWM_Init(void);
void PWM_SetFrequency(u16 freq_hz);
void PWM_UpdateDuty_R(void);
void PWM_UpdateDuty_G(void);
void PWM_UpdateDuty_B(void);
void IO_Init(void);
void KeyScan_R(void);
void KeyScan_G(void);
void KeyScan_B(void);
/*===========================================================================*/
// 函数名称: TIMR0_Init
// 功能描述: 初始化Timer0, 产生100us中断
/*===========================================================================*/
void TIMR0_Init(void)
{
// 关闭 Timer0 (清除 TOEN 位)
PCON1 &= ~PCON1_TOEN;
TMR0 = 231; // 100us 中断初值 (1us指令周期, 4分频)
// 配置 T0MD: 预分频器0分配给Timer0, 分频比1:4
T0MD = T0MD_CONFIG;
INTEbits.T0IE = 1; // 使能 Timer0 中断
// 启用 Timer0 (置位 TOEN)
PCON1 |= PCON1_TOEN;
}
/*===========================================================================*/
// 函数名称: PWM_Init
// 功能描述: 初始化三路硬件PWM (PWM1/PWM2/PWM3)
/*===========================================================================*/
void PWM_Init(void)
{
u16 period_val;
// 关闭 Timer1
T1CR1 = 0x00;
T1CR2 = 0x00;
// 计算周期值
period_val = (u16)(INSTRUCTION_FREQ / pwm_freq_hz) - 1;
if(period_val > 1023) period_val = 1023;
if(period_val < 1) period_val = 1;
// 写入周期值 (低8位在TMR1, 高2位在TMRH[1:0])
TMR1 = (u8)(period_val & 0xFF);
TMRH = (TMRH & 0xFC) | ((u8)(period_val >> 8) & 0x03);
// 使能 Timer1, 重载模式, PWM1输出, 预分频1:1
T1CR1 = T1EN | T1RL | PWM1OE | T1PS_1;
// 配置 PWM2 (红色)
P2CR1 = PWMxEN | PWMxS_TMR1;
PWM2DUTY = 0x00;
TMRH &= 0xF3; // 清零PWM2高2位 (TMRH[3:2])
// 配置 PWM3 (绿色)
P3CR1 = PWMxEN | PWMxS_TMR1;
PWM3DUTY = 0x00;
TM4RH &= 0xF3; // 清零PWM3高2位 (TM4RH[3:2])
// 配置 PWM1 (蓝色)
PWM1DUTY = 0x00;
TMRH &= 0xFC; // 清零PWM1高2位 (TMRH[1:0])
}
/*===========================================================================*/
// 函数名称: PWM_SetFrequency
// 功能描述: 动态修改三路PWM的频率
/*===========================================================================*/
void PWM_SetFrequency(u16 freq_hz)
{
u16 period_val;
if(freq_hz < MIN_PWM_FREQ) freq_hz = MIN_PWM_FREQ;
if(freq_hz > MAX_PWM_FREQ) freq_hz = MAX_PWM_FREQ;
pwm_freq_hz = freq_hz;
period_val = (u16)(INSTRUCTION_FREQ / freq_hz) - 1;
if(period_val > 1023) period_val = 1023;
if(period_val < 1) period_val = 1;
TMR1 = (u8)(period_val & 0xFF);
TMRH = (TMRH & 0xFC) | ((u8)(period_val >> 8) & 0x03);
}
/*===========================================================================*/
// 函数名称: PWM_UpdateDuty_R / _G / _B
// 功能描述: 根据亮度等级更新占空比 (0~1023)
/*===========================================================================*/
void PWM_UpdateDuty_R(void)
{
u16 duty = (u16)((u32)brightness_R * 1023 / (BRIGHTNESS_LEVELS - 1));
PWM2DUTY = (u8)(duty & 0xFF);
TMRH = (TMRH & 0xF3) | ((u8)(duty >> 6) & 0x0C);
}
void PWM_UpdateDuty_G(void)
{
u16 duty = (u16)((u32)brightness_G * 1023 / (BRIGHTNESS_LEVELS - 1));
PWM3DUTY = (u8)(duty & 0xFF);
TM4RH = (TM4RH & 0xF3) | ((u8)(duty >> 6) & 0x0C);
}
void PWM_UpdateDuty_B(void)
{
u16 duty = (u16)((u32)brightness_B * 1023 / (BRIGHTNESS_LEVELS - 1));
PWM1DUTY = (u8)(duty & 0xFF);
TMRH = (TMRH & 0xFC) | ((u8)(duty >> 8) & 0x03);
}
/*===========================================================================*/
// 函数名称: IO_Init
// 功能描述: 初始化IO口方向及上下拉电阻
/*===========================================================================*/
void IO_Init(void)
{
// 开漏全部关闭
BODCON = 0x00;
// 下拉全部关闭 (1=关)
ABPLCON = 0xFF;
PCONbits.PLPA4 = 1; // PA4 下拉关
APHCON |= 0x20; // PA5 下拉关 (位5置1)
// PA口上拉: PA6,PA0,PA1 开启上拉 (0=开)
APHCON = 0xFF; // 先全部关闭
APHCON &= ~((1<<6) | (1<<0) | (1<<1));
// PB口上拉全部关闭
BPHCON = 0xFF;
// 方向设置: PB1 输出, 其余输入
IOSTB = 0xFD; // 0b11111101
PORTB = 0x00;
// PA4,PA7 输出; PA6,PA0,PA1 输入
IOSTA = (1<<6) | (1<<0) | (1<<1); // 1=输入
PORTA = 0x00;
}
以下不内容详见附档文件
相关软件
小贴士
感谢您为本站写下的评论,您的评论对其它用户来说具有重要的参考价值,所以请认真填写。
- 类似“顶”、“沙发”之类没有营养的文字,对勤劳贡献的楼主来说是令人沮丧的反馈信息。
- 相信您也不想看到一排文字/表情墙,所以请不要反馈意义不大的重复字符,也请尽量不要纯表情的回复。
- 提问之前请再仔细看一遍楼主的说明,或许是您遗漏了。
- 请勿到处挖坑绊人、招贴广告。既占空间让人厌烦,又没人会搭理,于人于己都无利。
关于好例子网
本站旨在为广大IT学习爱好者提供一个非营利性互相学习交流分享平台。本站所有资源都可以被免费获取学习研究。本站资源来自网友分享,对搜索内容的合法性不具有预见性、识别性、控制性,仅供学习研究,请务必在下载后24小时内给予删除,不得用于其他任何用途,否则后果自负。基于互联网的特殊性,平台无法对用户传输的作品、信息、内容的权属或合法性、安全性、合规性、真实性、科学性、完整权、有效性等进行实质审查;无论平台是否已进行审查,用户均应自行承担因其传输的作品、信息、内容而可能或已经产生的侵权或权属纠纷等法律责任。本站所有资源不代表本站的观点或立场,基于网友分享,根据中国法律《信息网络传播权保护条例》第二十二与二十三条之规定,若资源存在侵权或相关问题请联系本站客服人员,点此联系我们。关于更多版权及免责申明参见 版权及免责申明


网友评论
我要评论