news 2026/7/27 20:42:18

【蓝桥杯单片机】第二讲 过渡模拟二与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/7/28 8:49:31

基于PSCAD EMTDC软件的风力发电机组控制系统仿真设计与验证

风力发电机控制系统仿真设计 风力发电系统动态模拟仿真 光伏发电系统 本设计主要依据风力发电机组的控制目标和控制策略&#xff0c;通过使用电力系统动态模拟仿真软件PSCAD/EMTDC&#xff0c;建立变桨距风力发电机组控制系统的模型。 为了验证控制系统模型的可用性&#xff0c…

作者头像 李华
网站建设 2026/7/28 9:02:26

基于PHP的画稿定制系统的设计与实现源码设计与文档

前言 基于 PHP 的画稿定制系统&#xff0c;直击 “用户需求表达模糊、画师资源分散、定制流程无保障” 的核心痛点&#xff0c;依托 PHP 的高效后端处理能力与 Laravel 框架的快速开发优势&#xff0c;构建 “需求匹配 创作协同 安全交易” 的一体化画稿定制服务平台。传统模…

作者头像 李华
网站建设 2026/7/26 19:52:08

Chat UI Kit React:30分钟搭建专业级聊天界面的终极指南

Chat UI Kit React&#xff1a;30分钟搭建专业级聊天界面的终极指南 【免费下载链接】chat-ui-kit-react Build your own chat UI with React components in few minutes. Chat UI Kit from chatscope is an open source UI toolkit for developing web chat applications. 项…

作者头像 李华
网站建设 2026/7/28 7:08:06

vfox插件管理完全指南:轻松掌握多版本工具切换技巧

vfox插件管理完全指南&#xff1a;轻松掌握多版本工具切换技巧 【免费下载链接】vfox 项目地址: https://gitcode.com/gh_mirrors/vf/vfox Version-Fox&#xff08;简称vfox&#xff09;是一款功能强大的跨平台版本管理器&#xff0c;专门解决开发者在不同项目间切换环…

作者头像 李华
网站建设 2026/7/24 14:23:05

语音转写技术在专业服务领域的应用实践

作为专业服务从业者&#xff0c;高效的信息记录与处理能力直接影响工作质量。以留学咨询行业为例&#xff0c;日常需要处理大量语音交流内容&#xff0c;传统手工记录方式不仅效率低下&#xff0c;还容易遗漏关键信息。本文将结合技术实现原理&#xff0c;探讨语音转写工具在专…

作者头像 李华
网站建设 2026/7/28 9:39:07

Cartographer SLAM系统实战指南:从零构建智能地图

Cartographer SLAM系统实战指南&#xff1a;从零构建智能地图 【免费下载链接】cartographer 项目地址: https://gitcode.com/gh_mirrors/car/cartographer 在机器人技术和自动驾驶领域&#xff0c;精准的环境感知与定位是核心技术挑战。Cartographer作为谷歌开源的SLA…

作者头像 李华