第九届蓝桥杯单片机省赛题彩灯

该代码是基于STC15F2K60S2单片机的程序,实现了IIC通信协议来驱动数码管和LED的显示。程序中包含了初始化函数、定时器设置、PWM亮度调节以及按键处理等功能,用于控制数码管的显示模式和LED的流转模式。同时,代码还支持通过PCF8591读取模拟信号来动态调整PWM占空比,实现亮度调节。
摘要由CSDN通过智能技术生成

参考佬中佬,但不搬运 !!!

 http://t.csdn.cn/4tnjz

#include <STC15F2K60S2.H>
#include <IIC.H>
sbit s7=P3^0;
sbit s6=P3^1;
sbit s5=P3^2;
sbit s4=P3^3;
#define u8 unsigned char
#define u16 unsigned int

u8 smg[8]={11,11,11,11,11,11,11,11};//初始显示10,全息数码管
u8 tab[]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90,0xbf,0xff};
u8 LED1[8]={0xfe,0xfd,0xfb,0xf7,0xef,0xdf,0xbf,0x7f}; //模式1
u8 LED2[8]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe}; //模式2
u8 LED3[4]={0x7e,0xbd,0xdb,0xe7}; //模式3
u8 LED4[4]={0xe7,0xdb,0xbd,0x7e}; //模式4
 
u16 smg_t;
u16 led_t;
u16 gap;
u8 num;

u8 smg_flag;
u8 smg_mode;

u8 led=0xff;
u8 led_mode;
u8 led_flag;

u8 pwm_duty;
u8 pwm_t;

u8 s6_sta;
u8 s7_flag;
u8 key_flag;
//============================初始化函数================================
void Delay1ms()		//@12.000MHz
{
	unsigned char i, j;
	i = 12;
	j = 169;
	do
	{
		while (--j);
	} while (--i);
}
void Delay5ms()		//@11.0592MHz
{
	unsigned char i, j;

	i = 54;
	j = 199;
	do
	{
		while (--j);
	} while (--i);
}
void Timer1Init(void)		//1毫秒@12.000MHz led流转
{
	AUXR &= 0xBF;		//定时器时钟12T模式
	TMOD &= 0x0F;		//设置定时器模式
	TL1 = 0x18;		//设置定时初值
	TH1 = 0xFC;		//设置定时初值
	TF1 = 0;		//清除TF1标志
	TR1 = 1;		//定时器1开始计时
	EA=1;ET1=1;
}
void Timer0Init(void)		//8毫秒@12.000MHz 扫描按键
{
	AUXR &= 0x7F;		//定时器时钟12T模式
	TMOD &= 0xF0;		//设置定时器模式
	TL0 = 0x60;		//设置定时初值
	TH0 = 0xF0;		//设置定时初值
	TF0 = 0;		//清除TF0标志
  TR0=1;//定时器0开始计时
	EA=1;ET0=1;
}
void Initsystem()
{
	P2=(P2&0x1f)|0x80;
	P0=0xff;
	P2=(P2&0x1f)|0xa0;
	P0=0x00;
	P2=(P2&0x1f)|0xc0;
	P0=0xff;
	P2=(P2&0x1f)|0xe0;
	P0=0xff;
}
//============================led流转================================
void  setled()
	{
		switch(led_mode)
						{
							case 1:if(num>=8)num=0;led=LED1[num];break;//led1
							case 2:if(num>=8)num=0;led=LED2[num];break;//led2
							case 3:if(num>=4)num=0;led=LED3[num];break;//led3
							case 4:if(num>=4)num=0;led=LED4[num];break;//led4
						}	
	}

void Timer1Service() interrupt 3
{
if(smg_mode==0)
  {
	if(s7_flag)
	{
	led_t++;

   //控制流转间隔
   if(led_t>=gap){
		  led_t=0; 
		 
		 if(led_flag) led_flag=0;
		 else{num++; led_flag=1;}
	  }
	 
	 if(led_flag) {
    //控制亮度
		  pwm_t++;
  		if(pwm_t==pwm_duty)
			 led=0xff;
      if(pwm_t==5)
	    {  	pwm_t=0; 	
		      setled();
	    }
		}
	else led=0xff;
	}
	else led=0xff;
}
else//数码管0.8s闪烁
	{
	led=0xff;
	smg_t++;
	if(smg_t>=800)
	{
		smg_t=0; smg_flag=~smg_flag;
	}
}
}
//============================PWm_duty调节================================
u8 PCF8591NUM()
{
	u8 Val;
	EA = 0;
	IIC_Start();				//IIC启动
	IIC_SendByte(0x90); 		//IIC选择地址,并发送写指令
	IIC_WaitAck();				//等待IIC应答
	IIC_SendByte(0x03);			//选择模拟量输入通道
	IIC_WaitAck();
	IIC_Stop();    				//IIC停止,接下来开始读取数据
	
	IIC_Start();				//IIC启动
	IIC_SendByte(0x91); 		//IIC选择地址,并发送读指令
	IIC_WaitAck();				//IIC等待应答
	Val = IIC_RecByte();		//接收PCF8591数据
	IIC_SendAck(1);				//发送应答位
	IIC_Stop();
	EA = 1;
	if(Val>=0&&Val<50)
		Val = 1;
	else if(Val>=50&&Val<100)
		Val = 2;
	else if(Val>=100&&Val<150)
		Val = 3;
	else if(Val>=150&&Val<256)
		Val = 4;
	/*根据所得ad值返回四种不同的数据给PWM*/
	return Val;
}
//============================数据保存================================
void eeprom_weite(u8 addr ,u8 val)
{

	IIC_Start();				//IIC启动
	IIC_SendByte(0xA0); 		//IIC选择地址,并发送写指令
	IIC_WaitAck();				//等待IIC应答
	IIC_SendByte(addr);			//选择模拟量输入通道
	IIC_WaitAck();
	IIC_SendByte(val); 
  IIC_WaitAck();
	IIC_Stop();    				//IIC停止,接下来开始读取数据
}
u8 eeprom_read(u8 addr)
{
	u8 Val;
	EA = 0;
	IIC_Start();				//IIC启动
	IIC_SendByte(0xA0); 		//IIC选择地址,并发送写指令
	IIC_WaitAck();				//等待IIC应答
	IIC_SendByte(addr);			//选择模拟量输入通道
	IIC_WaitAck();
  
  IIC_Start();				//IIC启动
	IIC_SendByte(0xA1); 		//IIC选择地址,并发送读指令
	IIC_WaitAck();				//IIC等待应答
	Val = IIC_RecByte();		//接收PCF8591数据
	IIC_SendAck(1);				//发送应答位
	IIC_Stop();
	EA=1;
 return Val;
}
//============================显示数码管================================	
void setgap()  //流转间隔数据
{
 if(gap>999)
 {
	 smg[4]=gap/1000;
	 smg[5]=gap/100%10;
 }
 else
 {
	 smg[4]=11;
	 smg[5]=gap/100;
  }
	 smg[6]=gap/10%10;
	 smg[7]=gap%10;
}	
void setsmg()  //显示界面
{
  switch(smg_mode)
	{
		case 0 : smg[0]= smg[1]=smg[2]= smg[3]=smg[4]= smg[5]=smg[6]= smg[7]=11;
		break;
		case 1 : smg[0]= smg[2]=10; smg[3]=11,  setgap(); 
		
		         if(smg_flag)  { smg[1]=led_mode; } 
						 else            smg[1]=11;
		break;
		case 2 : smg[0]= smg[2]=10; smg[3]=11;  smg[1]=led_mode; 
						 if(smg_flag)    setgap();
						 else          { smg[4]= smg[5]=smg[6]= smg[7]=11;}
    break;
	}
}
void outputsmg() //数码管输出
{
	u8 i;
	
	for(i=0;i<8;i++) {
	P2=(P2 &0x1f) |0xc0;
	P0=(1<<i);
	P2=(P2 &0x1f) |0xe0;
	P0=tab[smg[i]];
	Delay1ms();
	}
	P2=(P2 &0x1f) |0xc0;
	P0=0xff;
	P2=(P2 &0x1f) |0xe0;
	P0=0xff;
}
//============================按键处理================================
void Timeber0service() interrupt 1
{
key_flag=1;
}	


void scankey()
{
 if(key_flag)
 {
	 key_flag=0;
 if(s7==0)
	{
		while(s7==0);
   s7_flag=~s7_flag;
	}
  else if(s6==0)
  {
		switch(s6_sta)
		{
		case 0:  smg_mode=1; s6_sta=1; break;
		case 1:  smg_mode=2; s6_sta=2; break;
		case 2:  smg_mode=0;TR0=0; 	eeprom_weite(0x00,led_mode);	 Delay5ms();	eeprom_weite(0x01,gap/10);	TR0=1;  s6_sta=0;break;
		}
				while(s6==0){outputsmg();}
	}
	else if(s5==0)
	{
		while(s5==0){outputsmg();}
		switch(smg_mode)
		{
			case 1: if(led_mode>=4) led_mode=1;else led_mode+=1;  break; 
			case 2: if(gap>=1200) gap=100;else gap+=100; break;
	  }
	}
		else if(s4==0)
	{
     	while(s4==0){outputsmg();}
		switch(smg_mode)
		{	
			case 1: if(led_mode<=1) led_mode=1; else led_mode-=1; break; 
			case 2: if(gap<=100) gap=100; else gap-=100; break;
	  }	
  }
}
}
//============================main函数================================
void main()
{
	Timer1Init();
	Timer0Init();
	Initsystem();
	led_mode=eeprom_read(0x00); //上电数据读取
	gap=eeprom_read(0x01);
	gap*=10;
	while(1)
	{
		scankey(); 
		if(smg_mode) //数码管没有熄灭
    {
     setsmg(); 
		 outputsmg();
    }

	  else    //数码管熄灭
		{ 
    	 while(s4==0)  //长按S4
			 {
			 led=0xff; P2=0x80;
             smg[0]= smg[1]=smg[2]= smg[3]=smg[4]= smg[5]=11;
			 smg[6]=10; smg[7]= pwm_duty;
			 outputsmg();
			}
  	}
	  pwm_duty=PCF8591NUM();  //读取Pwm_duty
		P2=0x80;	P0=led;       //输出led值
}
}

驱动程序

/*
  程序说明: IIC总线驱动程序
  软件环境: Keil uVision 4.10 
  硬件环境: CT107单片机综合实训平台 8051,12MHz
  日    期: 2011-8-9
*/

#include "reg52.h"
#include "intrins.h"

#define DELAY_TIME 5

#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1

//总线引脚定义
sbit SDA = P2^1;  /* 数据线 */
sbit SCL = P2^0;  /* 时钟线 */

void IIC_Delay(unsigned char i)
{
    do{_nop_();}
    while(i--);        
}
//总线启动条件
void IIC_Start(void)
{
    SDA = 1;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 0;
    IIC_Delay(DELAY_TIME);
    SCL = 0;	
}

//总线停止条件
void IIC_Stop(void)
{
    SDA = 0;
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//发送应答
void IIC_SendAck(bit ackbit)
{
    SCL = 0;
    SDA = ackbit;  					// 0:应答,1:非应答
    IIC_Delay(DELAY_TIME);
    SCL = 1;
    IIC_Delay(DELAY_TIME);
    SCL = 0; 
    SDA = 1;
    IIC_Delay(DELAY_TIME);
}

//等待应答
bit IIC_WaitAck(void)
{
    bit ackbit;
	
    SCL  = 1;
    IIC_Delay(DELAY_TIME);
    ackbit = SDA;
    SCL = 0;
    IIC_Delay(DELAY_TIME);
    return ackbit;
}

//通过I2C总线发送数据
void IIC_SendByte(unsigned char byt)
{
    unsigned char i;

    for(i=0; i<8; i++)
    {
        SCL  = 0;
        IIC_Delay(DELAY_TIME);
        if(byt & 0x80) SDA  = 1;
        else SDA  = 0;
        IIC_Delay(DELAY_TIME);
        SCL = 1;
        byt <<= 1;
        IIC_Delay(DELAY_TIME);
    }
    SCL  = 0;  
}

//从I2C总线上接收数据
unsigned char IIC_RecByte(void)
{
    unsigned char i, da;
    for(i=0; i<8; i++)
    {   
    	SCL = 1;
	IIC_Delay(DELAY_TIME);
	da <<= 1;
	if(SDA) da |= 1;
	SCL = 0;
	IIC_Delay(DELAY_TIME);
    }
    return da;    
}
#ifndef _IIC_H_
#define _IIC_H_

void IIC_Start(void); 
void IIC_Stop(void);  
bit IIC_WaitAck(void);  
void IIC_SendAck(bit ackbit); 
void IIC_SendByte(unsigned char byt); 
unsigned char IIC_RecByte(void); 

#endif

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值