1、試題
一、基本要求
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 按鍵,數碼管顯示關閉, 亮度等級的顯示格式如下圖所示:
2、試題分析
模擬輸入:要掌握PCF8591芯片上的AD轉換。
按鍵控制:S7(P30),S6(P31),S5(P32),S4(P33)。
LED指示燈:初始化、P0端口低電平亮。
IIC總線控制、數碼管顯示。
E2PROM讀取斷電後的數據。
最後是PWM脈衝寬度調製技術控制led的亮度。對於PWM的解釋可見博客:
https://blog.csdn.net/fanjufei123456/article/details/105025590
還有一些細節上的連接問題,需要自己動手操作。
藍橋杯第九屆省賽和第八屆省賽,賽題還是比較相似的,按鍵控制方式都基本上一樣的模式,第八屆有實時時鐘、溫度傳感器等,第九屆是AD、IIC總線、EEPROM、PWM控制,另外PWM可能是個問題點。
3、代碼
iic.c
#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;
}
//等待應答
bit IIC_WaitAck(void)
{
SDA = 1;
somenop;
SCL = 1;
somenop;
if(SDA)
{
SCL = 0;
IIC_Stop();
return 0;
}
else
{
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;
}
unsigned char AD_Read(unsigned char add)
{
unsigned char temp;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
temp=IIC_RecByte();
IIC_Stop();
return temp;
}
//EEPROM讀
unsigned char EEPROM_Read(unsigned char add)
{
unsigned char temp;
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0xa1);
IIC_WaitAck();
temp=IIC_RecByte();
IIC_Stop();
return temp;
}
//EEPROMD寫
void EEPROM_Write(unsigned char dat,unsigned char add)
{
IIC_Start();
IIC_SendByte(0xa0);
IIC_WaitAck();
IIC_SendByte(add);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
iic.h
#ifndef _IIC_H
#define _IIC_H
#include "stc15f2k60s2.h"
#include "intrins.h"
#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();}
#define SlaveAddrW 0xA0
#define SlaveAddrR 0xA1
//總線引腳定義
sbit SDA = P2^1; /* 數據線 */
sbit SCL = P2^0; /* 時鐘線 */
//函數聲明
void IIC_Start(void);
void IIC_Stop(void);
void IIC_Ack(unsigned char ackbit);
void IIC_SendByte(unsigned char byt);
bit IIC_WaitAck(void);
unsigned char IIC_RecByte(void);
unsigned char AD_Read(unsigned char add);
unsigned char EEPROM_Read(unsigned char add);
void EEPROM_Write(unsigned char dat,unsigned char add);
#endif
text.c
#include<stc15f2k60s2.h>
#include "iic.h"
#define uchar unsigned char
#define uint unsigned int
uchar code tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,0XBF,0XFF};
uchar start=0;
uchar moshi=1;
uchar zhuanhua=0;
uint jiange=400;
uint led_t=0;
uint zhuanhua_t=0;
uint ad_t=0;
uint RB2=0;
uchar flag=0;
uchar led_n=0;
uchar led_TT=0,light=0;
uchar f1,f2,f3,f4,f5,f6,f7,f8;
void allinit();
void delayms(uchar ms);
void keyscan();
void Time0_init();
void display12(uchar f1,uchar f2);
void display34(uchar f3,uchar f4);
void display56(uchar f5,uchar f6);
void display78(uchar f7,uchar f8);
void main(){
allinit();
Time0_init();
moshi=EEPROM_Read(0x10);
delayms(5);
jiange=EEPROM_Read(0x20)*100;
delayms(5);
f1=11;f2=11;f3=11;f4=11;f5=11;f6=11;f7=11;f8=11;
while(1){
if((zhuanhua==0)&&(flag==1))
{
if(RB2<64)
{
f1=11;f2=11;f3=11;f4=11;f5=11;f6=11;f7=10;f8=1;
}
else if((RB2>=64)&&(RB2<128))
{
f1=11;f2=11;f3=11;f4=11;f5=11;f6=11;f7=10;f8=2;
}
else if((RB2>=128)&&(RB2<192))
{
f1=11;f2=11;f3=11;f4=11;f5=11;f6=11;f7=10;f8=3;
}
else if((RB2>=192)&&(RB2<255))
{
f1=11;f2=11;f3=11;f4=11;f5=11;f6=11;f7=10;f8=4;
}
}
else if(zhuanhua==0)
{
f1=11;f2=11;f3=11;f4=11;f5=11;f6=11;f7=11;f8=11;
}
keyscan();
display12(f1,f2);
display34(f3,f4);
display56(f5,f6);
display78(f7,f8);
}
}
void keyscan(){
if(P30==0)
{
delayms(5);
if(P30==0)
{
if(start==0)
{
start=1;
}
else if(start==1)
{
start=0;
}
}
while(!P30);
}
else if(P31==0)
{
delayms(5);
if(P31==0)
{
if(zhuanhua==0)
{
zhuanhua=1;zhuanhua_t=0;
if(jiange>=1000)
{
f1=10;f2=moshi;f3=10;f4=11;f5=jiange/1000;f6=jiange%1000/100;f7=jiange%100/10;f8=jiange%10;
}
else
{
f1=10;f2=moshi;f3=10;f4=11;f5=11;f6=jiange/100;f7=jiange%100/10;f8=jiange%10;
}
}
else if(zhuanhua==1)
{
zhuanhua=2;zhuanhua_t=0;
if(jiange>=1000)
{
f1=10;f2=moshi;f3=10;f4=11;f5=jiange/1000;f6=jiange%1000/100;f7=jiange%100/10;f8=jiange%10;
}
else
{
f1=10;f2=moshi;f3=10;f4=11;f5=11;f6=jiange/100;f7=jiange%100/10;f8=jiange%10;
}
}
else if(zhuanhua==2)
{
zhuanhua=0;zhuanhua_t=0;
f1=11;f2=11;f3=11;f4=11;f5=11;f6=11;f7=11;f8=11;
EEPROM_Write(moshi,0x10);
delayms(5);
EEPROM_Write(jiange/100,0x20);
delayms(5);
}
}
while(!P31);
}
else if(P32==0)
{
delayms(5);
if(P32==0)
{
if(zhuanhua==1)
{
moshi+=1;
if(moshi==5)
{
moshi=1;
}
}
else if(zhuanhua==2)
{
jiange+=100;
if(jiange==1300)
{
jiange=400;
}
}
}
while(!P32);
}
else if(P33==0)
{
delayms(5);
if(P33==0)
{
flag=1;
}
}
if((P33==1)&&(flag==1))
{
flag=0;
if(zhuanhua==1)
{
moshi-=1;
if(moshi==0)
{
moshi=4;
}
}
else if(zhuanhua==2)
{
jiange-=100;
if(jiange==300)
{
jiange=1200;
}
}
}
}
void Time0_init(){
TMOD=0X01;
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;
TR0=1;
EA=1;
ET0=1;
}
void Time0_service() interrupt 1
{
TH0=(65536-1000)/256;
TL0=(65536-1000)%256;
zhuanhua_t++;
led_t++;
ad_t++;
if((led_t==1)&&(start==1))
{
if(moshi==1)
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF;
P0=~(0X01<<led_n);
}
else if(moshi==2)
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF;
P0=~(0X80>>led_n);
}
else if(moshi==3)
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF;
if(led_n==0) P0=0X7E;
else if(led_n==1) P0=0XBD;
else if(led_n==2) P0=0XDB;
else if(led_n==3) P0=0XE7;
}
else if(moshi==4)
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF;
if(led_n==0) P0=0XE7;
else if(led_n==1) P0=0XDB;
else if(led_n==2) P0=0XBD;
else if(led_n==3) P0=0X7E;
}
}
else if(led_t==light)
{
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF;
}
else if(led_t==20)
{
led_t=0;led_TT++;
if(20*led_TT>=jiange)
{
led_TT=0;
if(moshi==1)
{
led_n++;
if(led_n>=8)
{
led_n=0;
}
}
else if(moshi==2)
{
led_n++;
if(led_n>=8)
{
led_n=0;
}
}
else if(moshi==3)
{
led_n++;
if(led_n>=4)
{
led_n=0;
}
}
else if(moshi==4)
{
led_n++;
if(led_n>=4)
{
led_n=0;
}
}
}
}
if(ad_t==200)
{
ad_t=0;
RB2=AD_Read(0x03);
if(RB2<64) light=2;
else if((RB2>=64)&&(RB2<128)) light=5;
else if((RB2>=128)&&(RB2<192)) light=10;
else if((RB2>=192)&&(RB2<255)) light=19;
}
if(zhuanhua_t==800)
{
if(zhuanhua==1)
{
if(jiange>=1000)
{
f1=11;f2=11;f3=11;f4=11;f5=jiange/1000;f6=jiange%1000/100;f7=jiange%100/10;f8=jiange%10;
}
else
{
f1=11;f2=11;f3=11;f4=11;f5=11;f6=jiange/100;f7=jiange%100/10;f8=jiange%10;
}
}
else if(zhuanhua==2)
{
if(jiange>=1000)
{
f1=10;f2=moshi;f3=10;f4=11;f5=11;f6=11;f7=11;f8=11;
}
else
{
f1=10;f2=moshi;f3=10;f4=11;f5=11;f6=11;f7=11;f8=11;
}
}
}
if(zhuanhua_t==1600)
{
zhuanhua_t=0;
if(zhuanhua==1)
{
if(jiange>=1000)
{
f1=10;f2=moshi;f3=10;f4=11;f5=jiange/1000;f6=jiange%1000/100;f7=jiange%100/10;f8=jiange%10;
}
else
{
f1=10;f2=moshi;f3=10;f4=11;f5=11;f6=jiange/100;f7=jiange%100/10;f8=jiange%10;
}
}
else if(zhuanhua==2)
{
if(jiange>=1000)
{
f1=10;f2=moshi;f3=10;f4=11;f5=jiange/1000;f6=jiange%1000/100;f7=jiange%100/10;f8=jiange%10;
}
else
{
f1=10;f2=moshi;f3=10;f4=11;f5=11;f6=jiange/100;f7=jiange%100/10;f8=jiange%10;
}
}
}
}
void allinit(){
P2=0XA0;P0=0X00;P2=0X80;P0=0XFF;
P2=0XC0;P0=0XFF;P2=0XFF;P0=0XFF;
}
void delayms(uchar ms){
uchar i,j,k;
for(k=ms;k>0;k--){
i=12;
j=169;
do
{
while(j--);
}
while(i--);
}
}
void display12(uchar f1,uchar f2){
P2=0XC0;P0=0X01;P2=0XFF;P0=tab[f1];
delayms(1);
P2=0XC0;P0=0X02;P2=0XFF;P0=tab[f2];
delayms(1);
}
void display34(uchar f3,uchar f4){
P2=0XC0;P0=0X04;P2=0XFF;P0=tab[f3];
delayms(1);
P2=0XC0;P0=0X08;P2=0XFF;P0=tab[f4];
delayms(1);
}
void display56(uchar f5,uchar f6){
P2=0XC0;P0=0X10;P2=0XFF;P0=tab[f5];
delayms(1);
P2=0XC0;P0=0X20;P2=0XFF;P0=tab[f6];
delayms(1);
}
void display78(uchar f7,uchar f8){
P2=0XC0;P0=0X40;P2=0XFF;P0=tab[f7];
delayms(1);
P2=0XC0;P0=0X80;P2=0XFF;P0=tab[f8];
delayms(1);
}