news 2026/4/23 12:47:50

【蓝桥杯单片机】第二讲 过渡模拟二与LED模块

作者头像

张小明

前端开发工程师

1.2k 24
文章封面图
【蓝桥杯单片机】第二讲 过渡模拟二与LED模块

一、过渡模拟二

1 小数点输入

case11://小数点输入if(Seg_Disp_Mode==0&&Point_Flag==0&&Seg_Input[0]!=11)//处于温度采集界面、标志位为0、输入数组第一位有数据{Seg_Point[2+Seg_Input_Index]=1;Point_Wela=Seg_Input_Index;//记录此时指针状态 便于后期数据处理Point_Flag=1;//拉高标志位 保证一次输入周期小数点只能使能一次}break;
Temperature=Seg_Input[0]*100+Seg_Input[1]*10+Seg_Input[2]+5;while(3-Point_Wela){Temperature/=10.0;Point_Wela++;}

2 长按短按不同功能

数码管的减速时间需要改成10ms(与按键一致),否则会出现间隔加不连贯的情况(按键在加,但数码管没刷新)

3 亮度等级

核心原理:欺骗眼睛的“视觉暂留”

  • 如果不控制:LED 只有“全亮”和“全灭”两种状态。
  • PWM大法:让 LED 快速地一会儿开、一会儿关。
    • 周期长(慢):人眼能看清,就是闪烁
    • 周期短(快):人眼看不清开关过程,觉得它一直在亮,只是亮度变暗了

关键术语:

  • 周期 (Period):比如把时间切成一小块一小块,每一块总长度是固定的(代码里是 10)。
  • 占空比 (Duty Cycle):在这一小块时间里,灯“亮”了多久。
    • 亮的时间越长 = 占空比越高 = 灯越
    • 亮的时间越短 = 占空比越低 = 灯越

把代码想象成一个切蛋糕的过程。我们要把一块蛋糕切成10 份(这就是周期)。

// 设定:我想让灯有 30% 的亮度 (Led_Pwm = 3)// 设定:蛋糕总共切 10 份 (上限是 10)unsignedcharLed_Num;// 现在的刀切到第几份了 (0~9)unsignedcharLed_Pwm;// 决定前几份蛋糕给灯吃 (亮度值)// 每执行一次,切下一份if(++Led_Num==10)Led_Num=0;// 切完10份,这就叫一个“周期”结束,重头开始// 核心判断:只要还没切到第 Led_Pwm 份,灯就亮着if(Led_Num<Led_Pwm)Led_Disp(Led_Pos,ucLed[Led_Pos]);// 【开灯】前 3 份时间亮elseLed_Disp(Led_Pos,0);// 【关灯】后 7 份时间灭

附:写程序过程中遇到的问题
  1. 数码管没有闪烁,只是先亮,然后一直灭

    错误代码及原因:

    if(Seg_Input[2]==11)Seg_Input[Seg_Input_Index]=Seg_Flag?Seg_Input[Seg_Input_Index]:10;

    这里不是对Seg_Input操作,是对Seg_Buf操作


代码实现

略有点小瑕疵,比如亮度等级(由于8ms才扫描一个灯,导致PWM不太对),但总体已实现功能

/* 头文件声明区 */#include<REGX52.H>//单片机寄存器专用头文件#include<Key.h>//按键底层驱动专用头文件#include<Seg.h>//数码管底层驱动专用头文件#include<Led.h>//Led底层驱动专用头文件/* 变量声明区 */unsignedcharKey_Val,Key_Down,Key_Old,Key_Up;//按键专用变量unsignedcharKey_Slow_Down;//按键减速专用变量unsignedcharSeg_Buf[6]={10,10,10,10,10,10};//数码管显示数据存放数组unsignedcharSeg_Pos;//数码管扫描专用变量unsignedcharSeg_Point[6]={0,0,0,0,0,0};//数码管小数点存放数组unsignedintSeg_Slow_Down;//数码管减速专用变量unsignedcharLed_Pos;//Led扫描专用变量unsignedcharLed[8]={0,0,0,0,0,0,0,0};//Led显示数据存放数组unsignedcharSeg_Disp_Mode;//0-温度采集界面 1-数据显示界面 2-参数设置界面unsignedcharSeg_Input[3]={11,11,11};unsignedcharSeg_Input_Index;unsignedintTimer_500ms;unsignedcharPoint_Wela;unsignedcharParameter[2]={30,20};unsignedcharParameter_Ctrol[2]={30,20};unsignedintTimer_Count;unsignedcharLed_Num;unsignedcharLed_PWM;floatTemperature;bit Seg_Flag;bit Point_Flag;bit Parameter_Index;bit Time_Flag;bit Error_Flag;/* 键盘处理函数 */voidKey_Proc(){unsignedchari;if(Key_Slow_Down)return;Key_Slow_Down=1;//键盘减速程序Key_Val=Key_Read();//实时读取键码值Key_Down=Key_Val&(Key_Old^Key_Val);//捕捉按键下降沿Key_Up=~Key_Val&(Key_Old^Key_Val);//捕捉按键上升沿Key_Old=Key_Val;//辅助扫描变量if(Key_Down>=1&&Key_Down<=10){if(Seg_Disp_Mode==0){Seg_Input[Seg_Input_Index]=Key_Down-1;Seg_Input_Index++;}}if(Seg_Disp_Mode==2){if(Key_Down==14)Time_Flag=1;}if(Timer_Count<500){if(Key_Up==14){Time_Flag=0;Timer_Count=0;if(++Parameter_Ctrol[Parameter_Index]>70)Parameter_Ctrol[Parameter_Index]=10;}}else{if(Key_Old==14){if(++Parameter_Ctrol[Parameter_Index]>70)Parameter_Ctrol[Parameter_Index]=10;if(Key_Up==14){Time_Flag=0;Timer_Count=0;}}}if(Seg_Disp_Mode==2){if(Key_Down==15)Time_Flag=1;}if(Timer_Count<500){if(Key_Up==15){Time_Flag=0;Timer_Count=0;if(--Parameter_Ctrol[Parameter_Index]<10)Parameter_Ctrol[Parameter_Index]=70;}}else{if(Key_Old==15){if(--Parameter_Ctrol[Parameter_Index]<10)Parameter_Ctrol[Parameter_Index]=70;if(Key_Up==15){Time_Flag=0;Timer_Count=0;}}}switch(Key_Down){case11:if(Seg_Disp_Mode==0&&Point_Flag==0&&Seg_Input[0]!=11){Seg_Point[2+Seg_Input_Index]=1;Point_Wela=Seg_Input_Index;Point_Flag=1;}break;case12:if(Seg_Disp_Mode!=0){Seg_Disp_Mode++;if(Seg_Disp_Mode>2)Seg_Disp_Mode=1;if(Seg_Disp_Mode==2){Parameter_Index=0;Parameter_Ctrol[0]=Parameter[0];Parameter_Ctrol[1]=Parameter[1];}else{if(Parameter_Ctrol[0]>=Parameter_Ctrol[1]){Error_Flag=1;Parameter[0]=Parameter_Ctrol[0];Parameter[1]=Parameter_Ctrol[1];}elseError_Flag=0;}}break;case13:if(Seg_Disp_Mode==2){Parameter_Index^=1;}break;case16:if(Seg_Disp_Mode==0){if(Point_Flag==0||Seg_Input_Index<3||Seg_Input[0]==0){Seg_Input_Index=0;for(i=0;i<3;i++)Seg_Input[i]=11;Point_Flag=0;Seg_Point[3]=Seg_Point[4]=0;}else{Temperature=Seg_Input[0]*100+Seg_Input[1]*10+Seg_Input[2]+5;if(Point_Wela==1)Temperature/=100.0;elseTemperature/=10.0;if((unsignedchar)Temperature<=85){Seg_Input_Index=0;Point_Flag=0;Seg_Point[3]=Seg_Point[4]=0;Seg_Disp_Mode=1;}else{Seg_Input_Index=0;for(i=0;i<3;i++)Seg_Input[i]=11;Point_Flag=0;Seg_Point[3]=Seg_Point[4]=0;}}}else{Seg_Input_Index=0;for(i=0;i<3;i++)Seg_Input[i]=11;Seg_Point[3]=Seg_Point[4]=0;Point_Flag=0;Seg_Disp_Mode=0;}}}/* 信息处理函数 */voidSeg_Proc(){unsignedchari;if(Seg_Slow_Down)return;Seg_Slow_Down=1;//数码管减速程序switch(Seg_Disp_Mode){case0:Seg_Buf[0]=12;Seg_Buf[1]=Seg_Buf[2]=10;for(i=0;i<3;i++)Seg_Buf[3+i]=Seg_Input[i];if(Seg_Input[2]==11)Seg_Buf[3+Seg_Input_Index]=Seg_Flag?Seg_Input[Seg_Input_Index]:10;break;case1:Seg_Buf[0]=13;Seg_Buf[1]=Seg_Buf[2]=Seg_Buf[3]=10;Seg_Buf[4]=(unsignedchar)Temperature/10%10;Seg_Buf[5]=(unsignedchar)Temperature%10;break;case2:Seg_Buf[0]=14;Seg_Buf[1]=10;Seg_Buf[2]=Parameter_Ctrol[0]/10;Seg_Buf[3]=Parameter_Ctrol[0]%10;Seg_Buf[4]=Parameter_Ctrol[1]/10;Seg_Buf[5]=Parameter_Ctrol[1]%10;if(!Parameter_Index){Seg_Buf[2]=Seg_Flag?Parameter_Ctrol[0]/10:10;Seg_Buf[3]=Seg_Flag?Parameter_Ctrol[0]%10:10;}else{Seg_Buf[4]=Seg_Flag?Parameter_Ctrol[1]/10:10;Seg_Buf[5]=Seg_Flag?Parameter_Ctrol[1]%10:10;}break;}}/* 其他显示函数 */voidLed_Proc(){if(Temperature>Parameter[0])Led_PWM=3;elseif(Temperature<Parameter[0]&&Temperature>Parameter[1])Led_PWM=6;elseLed_PWM=9;Led[0]=(int)Temperature/Parameter[0];Led[1]=(!((int)Temperature/Parameter[0]))&((int)Temperature/Parameter[1]);Led[2]=!((int)Temperature/Parameter[1]);Led[3]=Error_Flag;}/* 定时器0中断初始化函数 */voidTimer0Init(void)//1毫秒@12.000MHz{TMOD&=0xF0;//设置定时器模式TMOD|=0x01;//设置定时器模式TL0=0x18;//设置定时初始值TH0=0xFC;//设置定时初始值TF0=0;//清除TF0标志TR0=1;//定时器0开始计时ET0=1;//定时器0中断打开EA=1;//总中断打开}/* 定时器0中断服务函数 */voidTimer0Server()interrupt1{TL0=0x18;//设置定时初始值TH0=0xFC;//设置定时初始值if(++Key_Slow_Down==10)Key_Slow_Down=0;//键盘减速专用if(++Seg_Slow_Down==10)Seg_Slow_Down=0;//数码管减速专用if(++Seg_Pos==6)Seg_Pos=0;//数码管显示专用if(++Led_Pos==8)Led_Pos=0;//Led显示专用Seg_Disp(Seg_Pos,Seg_Buf[Seg_Pos],Seg_Point[Seg_Pos]);if(++Timer_500ms>=500){Timer_500ms=0;Seg_Flag^=1;}if(Time_Flag){if(++Timer_Count==600)Timer_Count=600;}if(++Led_Num==10)Led_Num=0;if(Led_Num<Led_PWM)Led_Disp(Led_Pos,Led[Led_Pos]);elseLed_Disp(Led_Pos,0);}/* Main */voidmain(){Timer0Init();while(1){Key_Proc();Seg_Proc();Led_Proc();}}

二、蓝桥杯LED模块

1 添加芯片头文件

  • 打开烧录工具STC-ISP

  • 进入"Keil仿真设置"

  • 选择单片机型号:IAP15F2K61S2

  • 点击添加型号和头文件到Keil中

  • 选择Keil的安装路径

2 锁存器

锁存器的作用是保存数据,防止数据在总线上变化时影响输出。

2.1 RS锁存器

Reset(复位) 和 Set(置位)。

  • R=1(使能), S=0 -> Q=0(复位)
  • R=0, S=1(使能) -> Q=1(置位)
  • R=0, S=0 -> 保持不变

真值表

RSQ
00Q
011
100
11X
2.2 D锁存器

EN=0时,输出状态保持不变

EN=1时,输出随输入状态而改变(当D=0,Q=0;当D=1,Q=1)

蓝桥杯板载芯片74HC573

八个锁存器都是D型锁存器

LE (Latch Enable):使能端,高电平有效。

LE = 1 (高电平):Q 跟随 D 变化 (直通模式)。

LE = 0 (低电平):Q 锁存住之前的数据,D 再变化 Q 也不变 (锁存模式)。

3 译码器

将 3 个输入引脚 (A, B, C) 转换成 8 个输出引脚 (Y0-Y7) 的低电平信号,用于选中不同的锁存器(片选)。

  • 连接方式:P25 -> A, P26 -> B, P27 -> C (高位对应高位)。
  • 输出特性:低电平有效。被选中的通道输出 0,其余输出 1。
蓝桥杯板载芯片74HC138

连接到P2口,P2高位在前(前三位:27、26、25)

真值表(基于8421BCD码)

输入 C (P27)输入 B (P26)输入 A (P25)选通输出 (低电平有效)功能映射 (蓝桥杯板)
000Y0未使用
001Y1未使用
010Y2未使用
011Y3未使用
100Y4LED控制
101Y5蜂鸣器/继电器
110Y6数码管位选
111Y7数码管段选

4 原理

先通过 P2 口的高 3 位控制译码器,选中对应的锁存器(LE置1),然后通过 P0 口写入数据,最后关闭锁存器(LE置0)。

5 编写程序

5.1 新建工程

选择芯片时需要先选择STC MCU Database

再选择15F2K60S2 Series

其余步骤与之前相同

5.2 关闭外设

原因:上电时 P0 口状态不确定,蜂鸣器可能会叫,继电器可能会吸合,LED可能会乱亮。初始化时需统一关闭。

init.c
#include<init.h>voidSystem_Init(){P0=0xff;P2=P2&0x1f|0x80;//先屏蔽低五位,再改变高三位P2&=0x1f;P0=0x00;P2=P2&0x1f|0xa0;P2&=0x1f;}
注释版init.c
#include<init.h>voidSystem_Init(){// 关闭 LED (Y4)P0=0xFF;// LED是低电平点亮,写入FF为全灭P2=(P2&0x1F)|0x80;// 保留P2低5位,将高3位设为 100 (Y4选中)P2&=0x1F;// 将高3位清零,关闭锁存器(LE=0)// 关闭蜂鸣器和继电器 (Y5)P0=0x00;// 蜂鸣器和继电器是高电平触发,写入00为全关P2=(P2&0x1F)|0xA0;// 保留P2低5位,将高3位设为 101 (Y5选中)P2&=0x1F;// 关闭锁存器}
init.h
#include<STC15F2K60S2.H>voidSystem_Init();
5.3 Led底层

为了避免在操作 LED 时影响其他 P2 口的设备(虽然在这个板子上基本只用高3位,但养成好习惯很重要),或者避免反复开关锁存器造成干扰。

Led.c
#include<Led.h>voidLed_Disp(unsignedcharaddr,unsignedcharenable){staticunsignedchartemp=0x00;staticunsignedchartemp_old=0xff;if(enable)temp|=0x01<<addr;elsetemp&=~(0x01<<addr);if(temp!=temp_old){P0=~temp;P2=P2&0x1f|0x80;P2&=0x1f;temp_old=temp;}}

注意static局部变量只在第一次初始化,后续调用函数时,它会记住上一次的值,非常适合保存外设状态。

注释版Led.c
#include<Led.h>/* @brief 控制指定位置的LED亮灭 @param addr LED位置 (0-7) @param enable 1-亮, 0-灭 */voidLed_Disp(unsignedcharaddr,unsignedcharenable){staticunsignedchartemp=0x00;// 记录当前的LED状态 (1表示亮)staticunsignedchartemp_old=0xff;// 记录上一次写入P0的值// 更新状态变量if(enable)temp|=(0x01<<addr);// 对应位置1elsetemp&=~(0x01<<addr);// 对应位置0// 只有当状态发生改变时,才操作硬件if(temp!=temp_old){P0=~temp;// 取反,因为LED是低电平点亮 (temp中1表示想让它亮,P0需输出0)// 打开Y4锁存器P2=(P2&0x1F)|0x80;// 关闭Y4锁存器P2&=0x1F;temp_old=temp;// 更新旧值}}
Led.h
#include<STC15F2K60S2.H>voidLed_Disp(unsignedcharaddr,unsignedcharenable);
5.4 主程序
//头文件声明区#include<Init.h>#include<Led.h>//Mainvoidmain(){System_Init();while(1){Led_Disp(0,1);}}
版权声明: 本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若内容造成侵权/违法违规/事实不符,请联系邮箱:809451989@qq.com进行投诉反馈,一经查实,立即删除!
网站建设 2026/4/23 12:47:23

涪陵区市电路灯批发报价与成本分析

在城市照明基础设施建设中&#xff0c;涪陵区近年来持续推进智慧化、绿色化升级&#xff0c;尤其在市电路灯系统的优化与更新方面成效显著。作为连接城市功能与居民生活的重要载体&#xff0c;路灯不仅承担基础照明任务&#xff0c;更需契合不同应用场景对光效、安全、节能及维…

作者头像 李华
网站建设 2026/4/22 19:35:42

光学工程师面试真题

一、基础理论与原理类1. 请解释数值孔径&#xff08;NA&#xff09; 的定义及计算公式&#xff0c;它对光学系统&#xff08;如显微镜、光纤&#xff09;的分辨率和通光量有何影响&#xff1f;2. 什么是光学镀膜的“增透膜”和“高反膜”&#xff1f;分别基于什么光学原理实现&…

作者头像 李华
网站建设 2026/4/16 16:17:15

文献检索网站有哪些:常用文献检索网站推荐与使用指南

开题报告前那两个月&#xff0c;我电脑里塞满了乱七八糟的PDF&#xff0c;参考文献格式错得千奇百怪&#xff0c;导师一句“脉络不清”打回来三次。后来才发现&#xff0c;问题不是读得不够多&#xff0c;而是工具没用对。这三个工具帮我理清了思路&#xff0c;把一堆文献变成了…

作者头像 李华
网站建设 2026/4/22 17:23:29

谷歌学术搜索:高效学术文献检索与研究资源获取指南

开题报告前那两个月&#xff0c;我电脑里塞满了乱七八糟的PDF&#xff0c;参考文献格式错得千奇百怪&#xff0c;导师一句“脉络不清”打回来三次。后来才发现&#xff0c;问题不是读得不够多&#xff0c;而是工具没用对。这三个工具帮我理清了思路&#xff0c;把一堆文献变成了…

作者头像 李华
网站建设 2026/4/22 22:32:25

学术搜索入口:快速获取权威学术资源的便捷通道

开题报告前那两个月&#xff0c;我电脑里塞满了乱七八糟的PDF&#xff0c;参考文献格式错得千奇百怪&#xff0c;导师一句“脉络不清”打回来三次。后来才发现&#xff0c;问题不是读得不够多&#xff0c;而是工具没用对。这三个工具帮我理清了思路&#xff0c;把一堆文献变成了…

作者头像 李华
网站建设 2026/4/17 22:04:35

常用免费文献检索网站推荐与使用指南

开题报告前那两个月&#xff0c;我电脑里塞满了乱七八糟的PDF&#xff0c;参考文献格式错得千奇百怪&#xff0c;导师一句“脉络不清”打回来三次。后来才发现&#xff0c;问题不是读得不够多&#xff0c;而是工具没用对。这三个工具帮我理清了思路&#xff0c;把一堆文献变成了…

作者头像 李华