2301_82038384 2023-12-25 16:06 采纳率: 0%
浏览 31
已结题

51单片机PWM可控灯程序设计

项目二:PWM可控灯设计
基本要求:基于单片机,采用PWM技术,进行亮度可调的可控灯制作与调试(要求同时调控2个或2个以上的多个发光二极管),编程实现可控灯的亮度增强和减弱,要求使用KEY1按键实现亮度增强调节,使用KEY2按键实现亮度减弱调节。
拓展要求:实现呼吸霓虹灯的设计,要求使用一个按键实现多花样、多呼吸频率(至少5种花样,其中至少3种不同呼吸频率)的呼吸霓虹灯花样切换变化(注意呼吸频率必须有明显变化)。

img

  • 写回答

4条回答 默认 最新

  • 技术宅program 2023-12-25 17:17
    关注
    #include <reg51.h> // 包含51单片机的头文件
    #define uchar unsigned char // 定义无符号字符类型
    #define uint unsigned int // 定义无符号整数类型
    #define LED P0 // 将LED灯连接到P0口
    #define KEY P1 // 将按键连接到P1口
    #define FREQ 100 // 定义PWM的频率为100Hz
    #define MODE 5 // 定义呼吸灯的模式个数
    #define DELAY 10 // 定义呼吸灯的延时常数
    
    uchar duty[8] = {0, 25, 50, 75, 100, 75, 50, 25}; // 定义8个LED灯的占空比数组
    uchar mode = 0; // 定义呼吸灯的模式变量,初始为0
    uchar speed = 1; // 定义呼吸灯的速度变量,初始为1
    uchar flag = 0; // 定义按键扫描的标志变量,初始为0
    
    void delay_ms(uint ms); // 延时函数的声明
    void pwm_output(); // PWM输出函数的声明
    void key_scan(); // 按键扫描函数的声明
    void mode_change(); // 模式切换函数的声明
    void speed_change(); // 速度改变函数的声明
    
    void main() // 主函数
    {
        TMOD = 0x01; // 设置定时器0为模式1
        TH0 = (65536 - 1000) / 256; // 设置定时器0的初值,定时10ms
        TL0 = (65536 - 1000) % 256;
        EA = 1; // 开启总中断
        ET0 = 1; // 开启定时器0中断
        TR0 = 1; // 启动定时器0
        while (1) // 主循环
        {
            key_scan(); // 调用按键扫描函数
            mode_change(); // 调用模式切换函数
            speed_change(); // 调用速度改变函数
        }
    }
    
    void delay_ms(uint ms) // 延时函数,延时ms毫秒
    {
        uint i, j;
        for (i = ms; i > 0; i--)
            for (j = 110; j > 0; j--);
    }
    
    void pwm_output() // PWM输出函数,根据占空比数组控制LED灯的亮度
    {
        uchar i;
        for (i = 0; i < 8; i++) // 循环遍历8个LED灯
        {
            if (duty[i] > 0) // 如果占空比大于0
            {
                LED = ~(1 << i); // 点亮对应的LED灯
                delay_ms(duty[i] * 10 / FREQ); // 延时占空比对应的时间
            }
            if (duty[i] < 100) // 如果占空比小于100
            {
                LED = 0xFF; // 熄灭所有的LED灯
                delay_ms((100 - duty[i]) * 10 / FREQ); // 延时剩余的时间
            }
        }
    }
    
    void key_scan() // 按键扫描函数,检测按键的状态
    {
        if (KEY != 0xFF) // 如果有按键按下
        {
            delay_ms(10); // 去抖延时
            if (KEY != 0xFF) // 再次判断按键状态
            {
                flag = KEY; // 记录按键值
                while (KEY != 0xFF); // 等待按键松开
            }
        }
    }
    
    void mode_change() // 模式切换函数,根据按键值改变呼吸灯的模式
    {
        if (flag == 0xFE) // 如果按下了KEY1
        {
            flag = 0; // 清除按键值
            mode++; // 模式加一
            if (mode == MODE) // 如果模式达到最大值
                mode = 0; // 模式归零
            switch (mode) // 根据模式值改变占空比数组
            {
            case 0: // 模式0,所有灯同时呼吸
                duty[0] = duty[1] = duty[2] = duty[3] = duty[4] = duty[5] = duty[6] = duty[7] = 0;
                break;
            case 1: // 模式1,单个灯依次呼吸
                duty[0] = 100;
                duty[1] = duty[2] = duty[3] = duty[4] = duty[5] = duty[6] = duty[7] = 0;
                break;
            case 2: // 模式2,两个灯依次呼吸
                duty[0] = duty[1] = 100;
                duty[2] = duty[3] = duty[4] = duty[5] = duty[6] = duty[7] = 0;
                break;
            case 3: // 模式3,四个灯依次呼吸
                duty[0] = duty[1] = duty[2] = duty[3] = 100;
                duty[4] = duty[5] = duty[6] = duty[7] = 0;
                break;
            case 4: // 模式4,八个灯依次呼吸
                duty[0] = duty[1] = duty[2] = duty[3] = duty[4] = duty[5] = duty[6] = duty[7] = 100;
                break;
            }
        }
    }
    
    void speed_change() // 速度改变函数,根据按键值改变呼吸灯的速度
    {
        if (flag == 0xFD) // 如果按下了KEY2
        {
            flag = 0; // 清除按键值
            speed++; // 速度加一
            if (speed == 4) // 如果速度达到最大值
                speed = 1; // 速度归一
        }
        switch (speed) // 根据速度值改变占空比数组
        {
        case 1: // 速度1,最慢
            duty[0]++;
            if (duty[0] == 100) // 如果占空比达到最大值
                duty[0] = 0; // 占空比归零
            break;
        case 2: // 速度2,较慢
            duty[0] += 2;
            if (duty[0] > 100) // 如果占空比超过最大值
                duty[0] = 0; // 占空比归零
            break;
        case 3: // 速度3,较快
            duty[0] += 5;
            if (duty[0] > 100) // 如果占空比超过最大值
                duty[0] = 0; // 占空比归零
            break;
        }
        if (mode > 0) // 如果模式不为0
        {
            uchar i;
            for (i = 1; i < 8; i++) // 循环遍历后面的灯
            {
                duty[i] = duty[i - 1]; // 将前一个灯的占空比赋值给后一个灯
            }
        }
        pwm_output(); // 调用PWM输出函数
    }
    
    void timer0() interrupt 1 // 定时器0中断服务函数
    {
        static char n; // 定义一个静态变量,用于记录PWM的状态
        if (n == 0) // 如果是第一次进入中断
        {
            OFF; // 关闭LED灯
            TH0 = (65536 - j) / 256; // 重新加载定时器0的初值,根据占空比计算低电平时间
            TL0 = (65536 - j) % 256;
            n = 1; // 改变状态变量
            return; // 退出中断
        }
        if (n == 1) // 如果是第二次进入中断
        {
            ON; // 打开LED灯
            TH0 = (65536 - k) / 256; // 重新加载定时器0的初值,根据占空比计算高电平时间
            TL0 = (65536 - k) % 256;
            n = 0; // 改变状态变量
            return; // 退出中断
        }
    }
    
    
    
    评论

报告相同问题?

问题事件

  • 已结题 (查看结题原因) 12月26日
  • 赞助了问题酬金15元 12月25日
  • 创建了问题 12月25日