Ⅰ
通过学习多位大佬的C语言编程控制单片机,今,我基于普中51-单核-A4开发板,利用步进电机模块来控制台灯的灯光亮度。
Ⅱ
2.1 目标:
①开发板四个独立按键控制台灯不同亮度(可以调多个档位,可调亮亦可调暗,异步控制两种的灯芯),
②开发板数码管显示档位与亮度占空比
2.2 C程序结构:
⑴需用模块:
①四个独立按键模块
②八个数码管模块
③定时计数器T0
④步进电机模块
⑵布局:
①主函数——识别独立按键消息+调整(PWM)亮占空比+数码管显示数据信息
② 中断函数——依据PWM周期和高电平(亮)占比控制台灯两个灯芯的亮度,赋定时计数器T0初值达到理想的PWM工作范围。(在极高速的亮灭变化下,肉眼无法感觉灯的闪烁,而一个周期内高电平所占宽度就决定灯的亮度)。
Ⅲ C程序:
3.1-1〈main文件〉头文件+变量
#include <REGX52.H>
#include "Key.h" //(普中51-单核-A4开发板)四个独立按键的读取头文件。
#include "Nixie.h" //八个数码管显示头文件
#include "Timer0.h" //定时计数器T0头文件
sbit light1=P1^0;
sbit light2=P1^1;
#define cycle 20 //设置(灯亮灭)PWM的周期值,周期越大则闪烁越明显(可以通过手机照相机观察到黑条。大于1000时人眼球侧看可以感觉到灯闪烁)
unsigned int HV[7]={0,1,4,8,12,15,20}; //设置亮宽度比值,总共可以设置7个,即:灯的亮度有七个挡位。
unsigned char Counter,T1_h,T2_h; //中断计数,灯1的亮宽,灯2的亮宽
unsigned char gears,remL1,remL2; //档位,记灯1前任,记灯2前任
unsigned int cut; //切换灯void
LightOFF(); //灯灭的服务函数
3.1-2〈main文件〉主函数
void main()
{
Timer0_Init(); //启动定时计数器T0,初始化
while(1)
{
/**************** 识别‘按键’并执行 **********************/
switch(Key())
{
case 1: gears++;if(gears>=7){gears=0;}; break; //按键1//加挡位,变亮
case 2: if(gears>0){gears--;}; break; //按键2//减挡位,变暗
case 3: LightOFF();break; //按键3//零档, 灯灭
case 4: cut++;cut%=2; //按键4//切换灯(对两盏灯选择)并保持被切换之前的亮度。
switch(cut) { case 0: gears=remL1;break;case 1: gears=remL2;break;};break;
}
/****************** 赋值相应的高电平占比 *************************/
if(gears<7)
{
gears%=7;
if(gears==0){switch(cut){ case 0:T1_h=HV[0];break; case 1:T2_h=HV[0]; break;}} //设置灯亮所占一个周期宽度(改变PWM占空比)
if(gears==1){switch(cut){ case 0:T1_h=HV[1];break; case 1:T2_h=HV[1]; break;}}
if(gears==2){switch(cut){ case 0:T1_h=HV[2];break; case 1:T2_h=HV[2]; break;}}
if(gears==3){switch(cut){ case 0:T1_h=HV[3];break; case 1:T2_h=HV[3]; break;}}
if(gears==4){switch(cut){ case 0:T1_h=HV[4];break; case 1:T2_h=HV[4]; break;}}
if(gears==5){switch(cut){ case 0:T1_h=HV[5];break; case 1:T2_h=HV[5]; break;}}
if(gears==6){switch(cut){ case 0:T1_h=HV[6];break; case 1:T2_h=HV[6]; break;}}
}
/****************** 数码管显示 *************************/
if(cut==0)
{
Nixie(1,cut); //数码管一:0表灯1、1表灯2
Nixie(5,gears); //数码管五:档位值
Nixie(8,(T1_h%100)%10); //数码管八,七,六:亮度占比值的百,十,个位数。
Nixie(7,(T1_h%100)/10);
Nixie(6,T1_h/100);
remL1=gears; //当前档位记到‘灯1前任’
}
else
{
Nixie(1,cut);
Nixie(5,gears);
Nixie(8,(T2_h%100)%10);
Nixie(7,(T2_h%100)/10);
Nixie(6,T2_h/100);
remL2=gears; //当前档位记到‘灯2前任’
}
}
}
3.1-3〈main文件〉灯灭函数
/**————————2—— 关闭两盏灯,且清除记忆,以便重新点亮灯 ——————————**/
void LightOFF(void)
{
T1_h=HV[0];
T2_h=HV[0];
gears=0;
remL1=0;
remL2=0;
}
3.1-4〈main文件〉中断服务函数
void Timer0_Routine() interrupt 1
{
TL0 = 0xD0; //赋定计器初值 执行中断服务:4uS/次
TH0 = 0xFF; //赋定计器初值
Counter++;
if(Counter>=cycle) //一个周期值为:cycle
Counter=0;
if(Counter<T1_h) //灯1亮占比值: T1_h
{
light1=1;
}
else //灯1灭占比值: cycle减T1_h
{
light1=0;
}
if(Counter<T2_h) //灯2亮占比值: T2_h
{
light2=1;
}
else //灯2灭占比值: cycle减T2_h
{
light2=0;
}
}
3.2-1〈KEY.h〉四个独立按键调用头
#ifndef __KEY_H__
#define __KEY_H__
unsigned char Key();
#endif
3.2-2〈KEY.c〉四独立按键C程序
/*********************************************/
/**对四个独立按键的识别,用到寄存器P3的四个位(P3^0、P3^1、P3^2、P3^3)**/
#include <REGX52.H>
void Delay(unsigned int xms);
/** * @brief 获取独立按键键码 * @param 无 * @retval 按下按键的键码,范围:0~4,无按键按下时返回值为0 */
unsigned char Key()
{
unsigned char KeyNumber=0;
if(P3_1==0){Delay(20);while(P3_1==0);Delay(20);KeyNumber=1;}
if(P3_0==0){Delay(20);while(P3_0==0);Delay(20);KeyNumber=2;}
if(P3_2==0){Delay(20);while(P3_2==0);Delay(20);KeyNumber=3;}
if(P3_3==0){Delay(20);while(P3_3==0);Delay(20);KeyNumber=4;}
return KeyNumber;
}
void Delay(unsigned int xms)
{
unsigned char i, j;
while(xms--)
{
i = 2;
j = 239;
do
{
while (--j);
} while (--i);
}
}
3.3-1〈NIXIE.h〉数码管显示头
#ifndef __NIXIE_H__
#define __NIXIE_H__
void Nixie(unsigned char Location,Number);
#endif
3.3-2〈NIXIE.c〉数码管显示C程序,(延时函数略)
/****************************************/
/**八个数码管扫描动态显示,用到寄存器P0和寄存器P2的三个位(P^2、P2^3、P2^4)。
**/
#include <REGX52.H>
#include "Delay.h"
//数码管段码表
unsigned char NixieTable[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
/**
* @brief 数码管显示
* * @param Location 要显示的位置,范围:1~8
* * @param Number 要显示的数字,范围:段码表索引范围
* * @retval 无
* */
void Nixie(unsigned char Location,Number)
{
switch(Location) //位码输出
{
case 1:P2_4=1;P2_3=1;P2_2=1;break;
case 2:P2_4=1;P2_3=1;P2_2=0;break;
case 3:P2_4=1;P2_3=0;P2_2=1;break;
case 4:P2_4=1;P2_3=0;P2_2=0;break;
case 5:P2_4=0;P2_3=1;P2_2=1;break;
case 6:P2_4=0;P2_3=1;P2_2=0;break;
case 7:P2_4=0;P2_3=0;P2_2=1;break;
case 8:P2_4=0;P2_3=0;P2_2=0;break;
}
P0=NixieTable[Number]; //段码输出
Delay(1); //显示一段时间
P0=0x00; //段码清0,消影
}
3.4-1〈Timer0.h〉定时计数器T0头
#ifndef __TIMER0_H__
#define __TIMER0_H__
void Timer0_Init(void);
#endif
3.4-2〈Timer0.c〉定时计数器T0C程序
#include <REGX52.H>
/**
* @brief 定时器0初始化,4us@12.000MHz
* * @param 无
* * @retval 无
* */
void Timer0_Init(void)
{
TMOD &= 0xF0; //设置定时器模式
TMOD |= 0x01; //设置定时器模式
TL0 = 0xD0; //设置定时初值 每4uS溢出一次
TH0 = 0xFF; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0=1;
EA=1;
PT0=1;
}
做该文章,出于个人欲了解CSDN,及与大家分享此程序思路。文章表达不清莫怪。希望同大家探讨该处涉及到的主要问题:于单片机开发板而言,在可按键控制灯的多档亮度的情况下,该如何编程,能完美的消除闪烁出现的黑条?
亮占比约4/20
亮占比约15/20
亮占比100%
百度网盘分享:源程序
链接:https://pan.baidu.com/s/15jOoL9YviYcFp6SzLBJPSA?pwd=1317
提取码:1317