蓝桥杯第九届省赛试题--“彩灯控制器”

题目要求

一、 基本要求
1.1 使用 CT107D 单片机竞赛板,完成“彩灯控制器” 功能的程序设计与调
试;
1.2 设计与调试过程中,可参考组委会提供的“资源数据包”;
1.3 Keil 工程文件以准考证号命名,完成设计后,提交完整、可编译的 Keil
工程文件到服务器。
二、 硬件框图
蓝桥杯第九届省赛试题--“彩灯控制器”_第1张图片
三、 功能描述
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:
蓝桥杯第九届省赛试题--“彩灯控制器”_第2张图片
4) 模式 4:
蓝桥杯第九届省赛试题--“彩灯控制器”_第3张图片
3.4 亮度等级控制
检测电位器 RB2 的输出电压,控制 8 个 LED 指示灯的亮度,要求在 0V-5V
的可调区间内,实现 4 个均匀分布的 LED 指示灯亮度等级。
3.5 按键功能
1) 按键 S7 定义为“启动/停止”按键,按下后启动或停止 LED 的流转。
2) 按键 S6 定义为“设置”按键,按键按下后数码管进入“流转间隔”,设置界面,如下图所示:
在这里插入图片描述
通过按键 S6 可切换选择“运行模式” 和“流转间隔” 两个显示单元,当前被选择的显示单元以 0.8 秒为间隔亮灭。
蓝桥杯第九届省赛试题--“彩灯控制器”_第4张图片
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;
}

以上就是代码全部内容,欢迎交流,共同学习~

你可能感兴趣的:(蓝桥杯)