一、 基本要求
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 "stc15f2k60s2.h"
#include "driver.h"
#include "iic.h"
#include "led.h"
#include "display.h"
unsigned char init_display[8];
unsigned char set_display[8];
unsigned char pwm_display[8];
bit led_enable;
bit smg_blink;
uchar led_value=0xff;
uchar mode_display; //显示模式
uchar PWM_VAL;
uchar set_switch; //设置选择 1 运行模式 2 流转间隔
uchar led_flash_mode=1; //led流水模式
uchar led_space=4; //led流转间隔
uchar test_2402;
void Timer0Init(); //1毫秒@11.0592MHz
void Timer1Init();
void delayms(uchar ms)
{
uint i,j;
for(i=0;i<ms;i++)
for(j=850;j>0;j--);
}
void main()
{
uchar key_value;
ALL_init();
Timer0Init();
Timer1Init();
Write_ADC(0x03);
while(1)
{
ET0=0;
test_2402=Read_2402(0x11);
if(test_2402==11)
{
led_flash_mode=Read_2402(0x00);
led_space=(Read_2402(0x01));
}
else
{
led_flash_mode=1;
led_space=4;
Write_2402(0x11,11);
delayms(5);
}
PWM_VAL=Read_ADC(0x03);
ET0=1;
init_mode();
set_mode();
led_flash();
pwm_mode();
key_value=key_init();
switch(key_value)
{
case 4:
set_mode_minus();
break;
case 5:
set_mode_add();
break;
case 6:
if(mode_display==0)
{
mode_display=1;
}
if(mode_display==1)
{
set_switch++;
if(set_switch==3)
{
set_switch=0;
mode_display=0;
}
}
break;
case 7:
led_enable=~led_enable;
break;
}
}
}
底层驱动程序
#include "driver.h"
void ALL_init() //板子初始化
{
P2=(P2&0X1F)|0XA0;
P0=0X00;
P2=(P2&0X1F)|0X80;
P0=0XFF;
P2=P2&0X1F;
}
void ledlight(uchar dat) //led
{
P0=0XFF;
P2=(P2&0X1F)|0X80;
P0=dat;
P2=P2&0X1F;
}
#define key_state0 0
#define key_state1 1
#define key_state2 2
uchar key_init() //按键
{
static uchar key_state=0;
uchar key_press, key_value=0;
key_press=P3&0X0F;
switch(key_state)
{
case key_state0:
if(key_press!=0x0f)
key_state=key_state1;
break;
case key_state1:
if(key_press!=0x0f)
{
if(key_press==0x0e) key_value=7;
if(key_press==0x0d) key_value=6;
if(key_press==0x0b) key_value=5;
if(key_press==0x07)
{
key_value=4;
if(mode_display!=1)
mode_display=2;
}
key_state=key_state2;
}
else
key_state=key_state0;
break;
case key_state2:
if(key_press==0x0f)
{
key_state=key_state0;
if(mode_display==2)
mode_display=0;
}
break;
}
return key_value;
}
led模块
只写了前面几种模式,其他模式原理相同
#include "led.h"
bit flag400ms,flag500ms,flag600ms,flag700ms,flag800ms;
bit flag900ms,flag1000ms;
bit flag1100ms,flag1200ms;
void led_flash() //led流水模式
{
unsigned char i,j,m,n,p,q,a,b;
if(led_enable) //允许led流转
{
switch(led_flash_mode)
{
case 1:
if(flag400ms)
{
flag400ms=0;
led_value=~(0x01<<i);
i++;
if(i==8)
i=0;
}
if(flag500ms)
{
flag500ms=0;
led_value=~(0x01<<j);
j++;
if(j==8)
j=0;
}
break;
case 2:
if(flag400ms)
{
flag400ms=0;
led_value=~(0x80>>m);
m++;
if(m==8)
m=0;
}
if(flag500ms)
{
flag500ms=0;
led_value=~(0x80>>n);
n++;
if(n==8)
n=0;
}
break;
case 3:
if(flag400ms)
{
flag400ms=0;
led_value=~((0x80>>p)|(0x01<<p));
p++;
if(p==4)
p=0;
}
if(flag500ms)
{
flag500ms=0;
led_value=~((0x80>>q)|(0x01<<q));
q++;
if(q==4)
q=0;
}
break;
case 4:
if(flag400ms)
{
flag400ms=0;
led_value=~((0x10>>a)|(0x08<<a));
a++;
if(a==5)
a=0;
}
if(flag500ms)
{
flag500ms=0;
led_value=~((0x10>>b)|(0x08<<b));
b++;
if(b==5)
b=0;
}
break;
}
}
}
void Timer1Init() //1毫秒@11.0592MHz
{
AUXR |= 0x40; //定时器时钟1T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0xCD; //设置定时初值
TH1 = 0xD4; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
EA=1;
ET1=1;
}
void timer1() interrupt 3
{
unsigned int count400ms,count500ms,count600ms,count700ms;
unsigned int count800ms,count900ms,count1000ms,count1100ms,count1200ms;
count400ms++; count500ms++; count600ms++;
count700ms++; count800ms++; count900ms++;
count1000ms++; count1100ms++; count1200ms++;
if(count400ms==400)
{
count400ms=0;
if(led_space==4)
flag400ms=1;
}
if(count500ms==500)
{
count500ms=0;
if(led_space==5)
flag500ms=1;
}
if(count600ms==600)
{
count600ms=0;
if(led_space==6)
flag600ms=1;
}
if(count700ms==700)
{
count700ms=0;
if(led_space==7)
flag700ms=1;
}
if(count800ms==800)
{
count800ms=0;
if(led_space==8)
flag800ms=1;
}
if(count900ms==900)
{
count900ms=0;
if(led_space==9)
flag900ms=1;
}
if(count1000ms==1000)
{
count1000ms=0;
if(led_space==10)
flag1000ms=1;
}
if(count1100ms==1100)
{
count1100ms=0;
if(led_space==11)
flag1100ms=1;
}
if(count1200ms==1200)
{
count1200ms=0;
if(led_space==12)
flag1200ms=1;
}
}
数码管显示模块
#include "display.h"
#include "driver.h"
#include "iic.h"
unsigned char code SMG_TAB[]={0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F};
unsigned char SMG_WEI[]={0X01,0X02,0X04,0X08,0X10,0X20,0X40,0X80};
void delay_ms(uchar ms)
{
uint i,j;
for(i=0;i<ms;i++)
for(j=850;j>0;j--);
}
void init_mode() //初始显示状态
{
init_display[0]=0x00; init_display[1]=0x00;
init_display[2]=0x00; init_display[3]=0x00;
init_display[4]=0x00; init_display[5]=0x00;
init_display[6]=0x00; init_display[7]=0x00;
}
void pwm_mode() //显示PWM
{
pwm_display[0]=0x00; pwm_display[1]=0x00;
pwm_display[2]=0x00; pwm_display[3]=0x00;
pwm_display[4]=0x00; pwm_display[5]=0x00;
pwm_display[6]=0x40; pwm_display[7]=SMG_TAB[PWM_VAL];
}
void set_mode_add() //加
{
if(mode_display==1)
{
if(set_switch==1)
{
led_flash_mode++;
if(led_flash_mode==5)
led_flash_mode=1;
Write_2402(0x00,led_flash_mode);
delay_ms(5);
}
if(set_switch==2)
{
led_space++;
if(led_space==13)
led_space=4;
Write_2402(0x01,led_space);
delay_ms(5);
}
}
}
void set_mode_minus() //减
{
if(mode_display==1) //设置界面
{
if(set_switch==1) //流水模式
{
if(led_flash_mode>1)
led_flash_mode--;
Write_2402(0x00,led_flash_mode);
delay_ms(5);
}
if(set_switch==2) //流水间隔
{
if(led_space>4)
led_space--;
Write_2402(0x01,led_space);
delay_ms(5);
}
}
}
void set_mode() //设置显示
{
set_display[0]=0x40;
set_display[2]=0x40; set_display[3]=0x00;
if(smg_blink)
{
if(set_switch==1)
set_display[1]=SMG_TAB[led_flash_mode];
if(set_switch==2)
{
if(led_space>9)
set_display[4]=SMG_TAB[led_space/10];
else
set_display[4]=0x00;
set_display[5]=SMG_TAB[led_space%10];
set_display[6]=SMG_TAB[0];
set_display[7]=SMG_TAB[0];
}
}
else
{
if(set_switch==1)
set_display[1]=0x00;
else
set_display[1]=SMG_TAB[led_flash_mode];
if(set_switch==2)
{
set_display[4]=0x00;
set_display[5]=0x00;
set_display[6]=0x00;
set_display[7]=0x00;
}
else
{
if(led_space>9)
set_display[4]=SMG_TAB[led_space/10];
else
set_display[4]=0x00;
set_display[5]=SMG_TAB[led_space%10];
set_display[6]=SMG_TAB[0];
set_display[7]=SMG_TAB[0];
}
}
}
void Timer0Init() //1毫秒@11.0592MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD &= 0xF0; //设置定时器模式
TL0 = 0xCD; //设置定时初值
TH0 = 0xD4; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
EA=1;
ET0=1;
}
void timer0() interrupt 1
{
uchar i;
uchar smg_count;
uchar hightime,hight_count;
uint set_count;
smg_count++;
set_count++;
hight_count++;
hight_count=hight_count&0x0f; //最大计数到15
if(smg_count==3)
{
smg_count=0;
P2=(P2&0X1F)|0XC0; P0=0X00;
P2=(P2&0X1F)|0XC0; P0=SMG_WEI[i];
P2=P2&0X1F;
if(mode_display==0)
{
P2=(P2&0X1F)|0XE0;
P0=~init_display[i];
P2=P2&0X1F;
}
if(mode_display==1)
{
P2=(P2&0X1F)|0XE0;
P0=~set_display[i];
P2=P2&0X1F;
}
if(mode_display==2)
{
P2=(P2&0X1F)|0XE0;
P0=~pwm_display[i];
P2=P2&0X1F;
}
i++;
if(i==8)
i=0;
}
if(set_count==400)
{
set_count=0;
smg_blink=~smg_blink;
}
hightime=PWM_VAL*PWM_VAL;
if(hight_count<hightime)
ledlight(led_value);
else
ledlight(0xff);
}
EEPROM模块
/*
程序说明: IIC总线驱动程序
软件环境: Keil uVision 4.10
硬件环境: CT107单片机综合实训平台(12MHz)
日 期: 2011-8-9
*/
#include "iic.h"
//总线启动条件
void IIC_Start(void)
{
SDA = 1;
SCL = 1;
somenop;
SDA = 0;
somenop;
SCL = 0;
}
//总线停止条件
void IIC_Stop(void)
{
SDA = 0;
SCL = 1;
somenop;
SDA = 1;
}
/*IIC总线协议规定,每传送一个字节数据后,都要有一个应答信号,以确定数据传送是否被对方收到,
应答信号由接收设备产生,在SCL为高电平期间,接收设备将SDA拉为低电平表示数据传输正确,即产生了应答。*/
//应答位控制
void IIC_Ack(unsigned char ackbit) //当ackbit为1时,表示单片机对从设备发送来数据的应答
//当ackbit为0时,表示主机接收了最后一个字节,因此不再应答,结束通信
{
if(ackbit)
{
SDA = 0;
}
else
{
SDA = 1;
}
somenop;
SCL = 1;
somenop;
SCL = 0;
SDA = 1;
somenop;
}
//等待应答
bit IIC_WaitAck(void)
{
SDA = 1;
somenop;
SCL = 1;
somenop;
if(SDA) //在SCL为高电平期间,因为接收设备未将SDA拉低,所以默认未接收到应答,结束IIC通信
{
SCL = 0;
IIC_Stop();
return 0;
}
else //接收到应答,返回1,继续下一个数据字节的传输
{
SCL = 0;
return 1;
}
}
//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
unsigned char i;
for(i=0;i<8;i++)
{
if(byt&0x80)
{
SDA = 1;
}
else
{
SDA = 0;
}
somenop;
SCL = 1;
byt <<= 1;
somenop;
SCL = 0;
}
}
//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++)
{
SCL = 1;
somenop;
da <<= 1;
if(SDA)
da |= 0x01;
SCL = 0;
somenop;
}
return da;
}
void Write_ADC(unsigned char dat)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
unsigned char Read_ADC(unsigned char dat)
{
unsigned char temp,pwm,val;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
temp=IIC_RecByte();
IIC_Ack(0);
IIC_Stop();
val=(temp*50)/255;
if((val>=38)&&(val<=50))
pwm=4;
else if((val>=26)&&(val<38))
pwm=3;
else if((val>=14)&&(val<26))
pwm=2;
else //if((val>=0)&&(val<14))
pwm=1;
return pwm;
}
void Write_2402(unsigned char addr, unsigned char dat)
{
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(addr);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
unsigned char Read_2402(unsigned char dat)
{
unsigned char temp;
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0xa1);
IIC_WaitAck();
temp=IIC_RecByte();
IIC_Ack(0);
IIC_Stop();
return temp;
}
以上就是代码全部内容,欢迎交流,共同学习~