“彩灯控制器”的程序设计与调试(70分)
一、基本要求
1.1 使用 CT107D 单片机竞赛板,完成“彩灯控制器”功能的程序设计与调试;
1.2 设计与调试过程中,可参考组委会提供的“资源数据包”;
1.3 Keil 工程文件以准考证号命名,完成设计后,提交完整、可编译的 Keil工程文件到服务器。
二、硬件框图
三、功能描述
3.1 基本功能描述
通过单片机控制8个LED指示灯按照特定的顺序(工作模式)亮灭;指示灯的流转间隔可通过按键调整,亮度可由电位器RB2进行控制;各工作模式的流转间隔时间需在E2PROM中保存,并可在硬件重新上电后,自动载入。
3.2 设计说明
1)关闭蜂鸣器、继电器等与本试题程序设计无关的外设资源;
2)设备上电后默认数码管、LED 指示灯均为熄灭状态;
3)流转间隔可调整范围为 400ms-1200ms;
4)设备固定按照模式 1、模式 2、模式 3、模式 4 的次序循环往复运行。
3.3 LED 指示灯工作模式
1)模式 1:按照 L1、L2…L8 的顺序,从左到右单循环点亮。
2)模式 2:按照 L8、L7…L1 的顺序,从右到左单循环点亮。
3)模式 3:
4)模式 4:
3.4 亮度等级控制
检测电位器RB2的输出电压,控制8个LED指示灯的亮度,要求在0V-5V
的可调区间内,实现 4 个均匀分布的 LED 指示灯亮度等级。
3.5 按键功能
1)按键 S7 定义为“启动/停止”按键,按下后启动或停止 LED 的流转。
2)按键 S6 定义为“设置”按键,按键按下后数码管进入“流转间隔”
设置界面,如下图所示:
通过按键 S6 可切换选择“运行模式”和“流转间隔”两个显示单元,
当前被选择的显示单元以 0.8 秒为间隔亮灭。
3)按键 S5 定义为“加”按键,在设置界面下,按下该键,若当前选择
的是运行模式,则运行模式编号加 1,若当前选择的是流转间隔,则
流转间隔增加 100ms。 4)按键 S4 定义为“减”按键,在设置界面下,按下该键,若当前选择
的是运行模式,则运行模式编号减 1,若当前选择的是流转间隔,则
流转间隔减少 100ms。 5)按键功能说明:
a)按键 S4、S5 的“加”、“减”功能只在“设置状态”下有效,数
值的调整应注意边界属性。
b)在非“设置状态”下,按下 S4 按键可显示指示灯当前的亮度等
级,4 个亮度等级从暗到亮,依次用数字 1、2、3、4 表示;松开
S4 按键,数码管显示关闭,亮度等级的显示格式如下图所示:
#include "base.h"
u8 SetInterface=0; //0:熄灭 1:模式编号 2:流转间隔
u8 modeNumber=1; //运行模式编号 1 2 3 4
u8 gaptime[]={0,4,4,4,4}; //流转间隔 400 500 ……1200
u8 LEDmode1[9]={0xff,0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};
u8 LEDmode2[8]={0x80,0x40,0x20,0x10,0x08,0x04,0x02,0x01};
u8 LEDmode3[4]={0x81,0x42,0x24,0x18};
u8 LEDmode4[4]={0x18,0x24,0x42,0x81};
u8 PWMflag=10; //1 4 7 10
u8 ShowBrightness=4; //1 2 3 4
u8 P0temp=0xff;
u8 Rb2;
bit Flag800ms;
u8 KeyNumber;
u8 i;
u16 LEDdelay=0;
u8 LEDmode=0;//LED亮的运行模式编号 1 2 3 4
bit LEDpause=1; //1:启动 0:停止
void main()
{
Init_System();
InitTimer0();
for(i=1;i<5;i++)
{
gaptime[i]=AT24C02_ReadByte(i);
Delay6ms();
if(gaptime[i]>12 || gaptime[i]<4)
{
gaptime[i]=4;
}
}
while(1)
{
//=================PWM=====
Rb2=Read_Rb2(3);
if(Rb2 < 64)
{
PWMflag=1;ShowBrightness=1;
}
else if(Rb2 < 128)
{
PWMflag=4;ShowBrightness=2;
}
else if(Rb2 < 192)
{
PWMflag=7;ShowBrightness=3;
}
else
{
PWMflag=10;ShowBrightness=4;
}
//============================按键======================
KeyNumber=Key();
/*7*/ if(KeyNumber==7) //启动,停止
{
LEDpause=~LEDpause;
}
/*6*/ if(KeyNumber==6) //换模式编号,流转间隔,熄灭
{
SetInterface=(SetInterface+1)%3;
LEDmode=1;
}
/*5*/ if(KeyNumber==5) //模式+1 或 间隔+1
{
if(SetInterface==1)
{
modeNumber++;
if(modeNumber==5)
{
modeNumber=1;
}
}
else if(SetInterface==2)
{
gaptime[modeNumber]++;
if(gaptime[modeNumber]==13)
{
gaptime[modeNumber]=4;
}
}
}
/*4*/ if(KeyNumber==4) //模式-1 或 间隔-1
{
if(SetInterface==1)
{
modeNumber--;
if(modeNumber==0)
{
modeNumber=4;
}
}
else if(SetInterface==2)
{
gaptime[modeNumber]--;
if(gaptime[modeNumber]==3)
{
gaptime[modeNumber]=12;
}
}
}
//============================AT24C02======================
for(i=1;i<5;i++)
{
AT24C02_WriteByte(i,gaptime[i]);
Delay6ms(); //!!!要记得写入后延时6ms
}
//============================display======================
if(P33==0 && SetInterface==0)
{
DisplayBrightness(ShowBrightness);
}
else
{
DisplaySet(modeNumber,gaptime[modeNumber]);
}
}//while(1)
}
//tm0_isr 1ms
void tm0_isr() interrupt 1
{
static u16 cnt=0;
static u8 LEDbit=0; //第几个LED亮L1~L8
cnt++;
TL0=65535-12000;
TH0=(65535-12000)>>8;
Display_scan();
//=====================================PWM=======
if(cnt%10 < PWMflag) //亮
{
P0=P0temp;Y4;
}
else //灭
{
P0=0xFF;Y4;
}
//=====================================PWMend=======
if(cnt%20==0)
{
Key_scan();
}
if(cnt%800==0)
{
Flag800ms=~Flag800ms;
}
//=================LED=============
if( SetInterface==0 && LEDpause==1)//0:熄灭 1:模式编号 2:流转间隔
{
if(cnt % (gaptime[1]*100)==0 && LEDmode==1)
{
LEDbit++;
P0temp=~LEDmode1[LEDbit];Y4;
if(LEDbit==8)
{
LEDbit=0;LEDmode=2;
}
}
else if(cnt % (gaptime[2]*100)==0 && LEDmode==2)
{
P0temp=~LEDmode2[LEDbit];Y4;
LEDbit++;
if(LEDbit==8)
{
LEDbit=0;LEDmode=3;
}
}
else if(cnt % (gaptime[3]*100)==0 && LEDmode==3)
{
P0temp=~LEDmode3[LEDbit];Y4;
LEDbit++;
if(LEDbit==4)
{
LEDbit=0;LEDmode=4;
}
}
else if(cnt % (gaptime[4]*100)==0 && LEDmode==4)
{
P0temp=~LEDmode4[LEDbit];Y4;
LEDbit++;
if(LEDbit==4)
{
LEDbit=0;LEDmode=1;
}
}
}
//=========================LEDend===============
cnt%=1200;
}
模块
#include "base.h"
u8 NixieTab[10]={0xC0,0xF9,0xA4,0xB0,0x99,0x92,0x82,0xF8,0x80,0x90};
u8 show_Buffer[]={0xff,0xff,0xff,0xff,0xff,0xff,0xff,0xff};
/*
0 -- 0xC0
1 -- 0xF9
2 -- 0xA4
3 -- 0xB0
4 -- 0x99
5 -- 0x92
6 -- 0x82
7 -- 0xF8
8 -- 0x80
9 -- 0x90
*/
void Init_System()
{
P0=0x00;Y6;
P0=0xff;Y7;
P0=0x00;Y5;
P0=0xff;Y4;
}
void InitTimer0()
{
AUXR |= 0x80;
TMOD=0x01;
TL0=65535-11059;
TH0=(65535-11059)>>8;
TR0=1;
ET0=1;
EA=1;
}
void Display_scan()
{
static u8 SMGvalue;
P0=0x01<<SMGvalue;Y6;
P0=show_Buffer[SMGvalue];Y7;
SMGvalue=(SMGvalue+1)%8;
}
extern bit Flag800ms;
extern u8 SetInterface;
void DisplaySet(u8 mode,u16 time)
{
if(SetInterface==0)
{
show_Buffer[0]=0xff;
show_Buffer[1]=0xff;
show_Buffer[2]=0xff;
show_Buffer[4]=0xff;
show_Buffer[5]=0xff;
show_Buffer[6]=0xff;
show_Buffer[7]=0xff;
}
else if(Flag800ms==0 && SetInterface==1)
{
show_Buffer[0]=0xff;
show_Buffer[1]=0xff;
show_Buffer[2]=0xff;
}
else if(Flag800ms==0 && SetInterface==2)
{
show_Buffer[4]=0xff;
show_Buffer[5]=0xff;
show_Buffer[6]=0xff;
show_Buffer[7]=0xff;
}
else
{
show_Buffer[0]=0xBF;
show_Buffer[1]=NixieTab[mode%10];
show_Buffer[2]=0xBF;
if(time/10%10==0)
{
show_Buffer[4]=0xff;
}
else
{
show_Buffer[4]=NixieTab[time/10%10];
}
show_Buffer[5]=NixieTab[time%10];
show_Buffer[6]=NixieTab[time*10%10];
show_Buffer[7]=NixieTab[time*100%10];
}
}
void DisplayBrightness(u8 ShowBrightness)
{
show_Buffer[6]=0xbf;
show_Buffer[7]=NixieTab[ShowBrightness];
}
u8 KeyNum;
u8 getKey()
{
u8 getKey=0; //必须=0,要不会出问题
if(P30==0){getKey=7;}
if(P31==0){getKey=6;}
if(P32==0){getKey=5;}
if(P33==0){getKey=4;}
return getKey;
}
void Key_scan()
{
static u8 LastKey,NowKey;
LastKey=NowKey;
NowKey=getKey();
if(LastKey==7 && NowKey==0) //S7按下
{
KeyNum=7;
}
if(LastKey==6 && NowKey==0)
{
KeyNum=6;
}
if(LastKey==5 && NowKey==0)
{
KeyNum=5;
}
if(LastKey==4 && NowKey==0)
{
KeyNum=4;
}
// return KeyNum;
}
u8 Key()
{
u8 Key;
Key=KeyNum;
KeyNum=0;
return Key;
}
//==================================AT24C02==================================
void Delay6ms() //@12.000MHz
{
unsigned char i, j;
i = 71;
j = 6;
do
{
while (--j);
} while (--i);
}
void AT24C02_WriteByte(u8 WordAddress,Data)
{
I2CStart();
I2CSendByte(0xA0);
I2CWaitAck();
I2CSendByte(WordAddress);
I2CWaitAck();
I2CSendByte(Data);
I2CWaitAck();
I2CStop();
}
u8 AT24C02_ReadByte(u8 WordAddress)
{
u8 Data;
I2CStart();
I2CSendByte(0xA0);
I2CWaitAck();
I2CSendByte(WordAddress);
I2CWaitAck();
I2CStart();
I2CSendByte(0xA1);
I2CWaitAck();
Data=I2CReceiveByte();
I2CSendAck(1);
I2CStop();
return Data;
}
//==============================PCF8591======================================
u8 Read_Rb2(u8 WordAddress)
{
u8 Data;
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(WordAddress);
I2CWaitAck();
I2CStop();
I2CStart();
I2CSendByte(0x91);
I2CWaitAck();
Data=I2CReceiveByte();
I2CSendAck(1);
I2CStop();
return Data;
}
官方提供的iic文件
/* # I2C代码片段说明
1. 本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
2. 参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include "base.h"
#include "iic.h"
#define DELAY_TIME 5
sbit scl=P2^0;
sbit sda=P2^1;
//
static void I2C_Delay(unsigned char n)
{
do
{
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
}
while(n--);
}
//
void I2CStart(void)
{
sda = 1;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 0;
I2C_Delay(DELAY_TIME);
scl = 0;
}
//
void I2CStop(void)
{
sda = 0;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 1;
I2C_Delay(DELAY_TIME);
}
//
void I2CSendByte(unsigned char byt)
{
unsigned char i;
for(i=0; i<8; i++){
scl = 0;
I2C_Delay(DELAY_TIME);
if(byt & 0x80){
sda = 1;
}
else{
sda = 0;
}
I2C_Delay(DELAY_TIME);
scl = 1;
byt <<= 1;
I2C_Delay(DELAY_TIME);
}
scl = 0;
}
//
unsigned char I2CReceiveByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++){
scl = 1;
I2C_Delay(DELAY_TIME);
da <<= 1;
if(sda)
da |= 0x01;
scl = 0;
I2C_Delay(DELAY_TIME);
}
return da;
}
//
unsigned char I2CWaitAck(void)
{
unsigned char ackbit;
scl = 1;
I2C_Delay(DELAY_TIME);
ackbit = sda;
scl = 0;
I2C_Delay(DELAY_TIME);
return ackbit;
}
//
void I2CSendAck(unsigned char ackbit)
{
scl = 0;
sda = ackbit;
I2C_Delay(DELAY_TIME);
scl = 1;
I2C_Delay(DELAY_TIME);
scl = 0;
sda = 1;
I2C_Delay(DELAY_TIME);
}