@**[蓝桥杯](单片机设计组第十届省赛)
这是我写的第一篇文章,不好的地方还请大家见谅,有什么问题欢迎评论留言,共同学习共同进步~
说明:
本次省赛涉及到 PCF8591的AD和DA功能,测量RB2(对应通道3)的电压,NE555测频功能,使用T0作为计数器,使用定时器T1产生1s的门控信号,对NE555的输出SIGNAL进行计数,完成频率测量。
程序设计题目:
历年省赛试题
提取码:asdf
代码:
1 、main.c
#include "STC15F2K60S2.H"
#include "key.h"
#include "iic.h"
#define u8 unsigned char
#define u16 unsigned int
/**********
函数声明
*******/
void system_init();
void count_0_init();
void timer_1_init();
void smg_display(unsigned char what[]);
void key_processing();
void led_processing();
/**************
变量定义
************/
u8 code smg_duan[]={ //标准字库
// 0 1 2 3 4 5 6 7 8 9
0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,
0xBF,0X86,0XDB,0XCF,0XE6,0XED,0XFD,0X87,0XFF,0XEF,0X40,0X00,0X71,0X3E };
// 0. 1. 2. 3. 4. 5. 6. 7. 8. 9. - 灭 F U
u8 code smg_wei[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80}; //位码 0111 0001
u8 smg_buff[8];
u8 frequency_array[8] = {22,21,21,21,21,21,21,21};
u8 voltage_array[8] = {23,21,21,21,21,21,21,21};
bit count_10ms_flag = 0 , adc_flag = 0 ,led_EN = 0 ,smg_EN = 0 ,DA_index = 0;
u8 key_vaule = 0 ;
u16 adc_vaule = 0 ;
u8 menu_index = 1 ;
u16 frequency_count = 0;
u16 frequency = 0 ;
/******
主程序
************/
void main()
{
system_init();
count_0_init();
timer_1_init(); // 1 ms
while(1)
{
if(adc_flag == 1)
{
adc_flag = 0 ;
adc_vaule = (u16)(read_adc(0x03) * 1.917) ; // 1 / 255 * 4.89 * 100 = 1.917 :-->数字0~255转化为电压 0~489 单位 0.01V
voltage_array[5] = adc_vaule / 100 + 10; // 带小数点的 adc_vaule 的百位
voltage_array[6] = adc_vaule / 10 % 10 ;
voltage_array[7] = adc_vaule % 10 ;
if(DA_index == 0) // 固定 DAC 2.0 V
{
write_dac((2.0+0.05)*51);
}
else // 跟 随 A D 输出
{
if(( adc_vaule + 2 ) * 0.521 > 255)
write_dac(255);
else
write_dac(( adc_vaule + 2 ) * 0.521 );
}
led_processing();
}
key_processing();
}
}
/*******
计 数 器 0 中 断 服务 子 程 序
**********/
void count_0_INT_processing() interrupt 1
{
frequency_count++;
}
/*******
定 时 器 1 中 断 服务 子 程 序
**********/
void timer_1_INT_processing() interrupt 3
{
static int count_2ms = 0 , count_10ms = 0 , count_1000ms = 0 ;
u8 dat_index = 0 ;
count_2ms++; count_10ms++; count_1000ms++;
if(count_2ms == 2)
{
count_2ms = 0 ;
smg_display(smg_buff); // 调 用 显 示 子 程 序
}
if(count_10ms == 10)
{
count_10ms = 0 ;
count_10ms_flag = 1 ;
adc_flag = 1 ;
}
if(count_1000ms == 1000)
{
count_1000ms = 0 ;
TR0 = 0 ;
ET0 = 0 ;
frequency = frequency_count ;
frequency_array[2] = frequency_count / 100000 ;
frequency_array[3] = frequency_count / 10000 % 10 ;
frequency_array[4] = frequency_count / 1000 % 10 ;
frequency_array[5] = frequency_count / 100 % 10 ;
frequency_array[6] = frequency_count / 10 % 10 ;
frequency_array[7] = frequency_count % 10 ;
dat_index = 2 ;
while(frequency_array[dat_index] == 0)
{
frequency_array[dat_index] = 21 ;
dat_index ++ ;
}
frequency_count = 0 ;
ET0 = 1 ;
TR0 = 1 ;
}
}
/*********************
*******显示子程序 ****
******* ******
*********/
void smg_display(u8 what[])
{
static int where = 0 ;
u8 i = 0 ;
for(i = 0 ; i < 8 ; i++)
{
if(smg_EN == 1)
{
switch(menu_index)
{
case(1): what[i] = ~smg_duan[voltage_array[i]] ;break ;
case(2): what[i] = ~smg_duan[frequency_array[i]] ;break ;
}
}
else
{
what[i] = ~smg_duan[21];
}
}
P2 = 0X00 ; P0 = 0x00 ; P2 = 0XC0 ;
P2 = 0X00 ; P0 = smg_wei[where] ; P2 = 0XC0 ;
P2 = 0X00 ; P0 = what[where]; P2 = 0XE0 ;
where++;if(where == 8)where = 0 ;
}
/*
********************
******led 子 程 序 ****
************************
*/
void led_processing()
{
u8 led_return ;
if(led_EN == 1)
{
if(menu_index == 0)led_EN = 0 ;
else if(menu_index == 1)
{
if(DA_index == 0)
{
if((adc_vaule < 150) || ( (adc_vaule >= 250) && (adc_vaule < 350 ) ))
led_return = 0xfe ;
else
led_return = 0xfa ;
}
else
{
if((adc_vaule < 150) || ( (adc_vaule >= 250) && (adc_vaule < 350 ) ))
led_return = 0xee ;
else
led_return = 0xea ;
}
}
else
{
if((frequency < 1000) || ( (frequency >= 5000) && (frequency < 10000 ) ))
led_return = 0xfd;
else
led_return = 0xf5;
}
P2 = 0X00 ; P0 = led_return; P2 = 0x80 ;
}
else
{
P2 = 0X00 ; P0 = 0xff; P2 = 0x80 ;
}
}
/*********************
*****按 键 处理 *******
*************
*********/
void key_processing()
{
if(count_10ms_flag == 1)
{
count_10ms_flag = 0 ;
key_vaule = key_btn();
switch(key_vaule)
{
case(4):menu_index ++ ;
if(menu_index ==3)menu_index =1 ;
break;
case(5):DA_index = !DA_index ;
break;
case(6):led_EN = !led_EN ;
break;
case(7):smg_EN = !smg_EN ;
break;
}
}
}
/*********************
*****初 始 化 *******
*************
*********/
void count_0_init()
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD = (TMOD & 0XF0) | 0x04; //设置定时器模式------方式0 计数
TL0 = 0xff; //设置定时初值
TH0 = 0xff; //设置定时初值
TF0 = 0; //清除TF0标志
TR0 = 1; //定时器0开始计时
ET0 = 1 ;
EA = 1 ;
}
void timer_1_init()
{
AUXR |= 0x40; //定时器时钟1T模式
TMOD = (TMOD & 0X0F) ; //设置定时器模式------方式0 计数
TL1 = 0x20; //设置定时初值
TH1 = 0xd1; //设置定时初值
TF1 = 0; //清除TF0标志
TR1 = 1; //定时器0开始计时
ET1 = 1 ;
EA = 1 ;
}
void system_init()
{
/*
注:先将 P2 = 0X00 可以预防在P0口赋值后的相对短的一段时间里
其他外设的状态发生预期之外的变化
*/
P2 = 0X00 ; P0 = 0XFF ; P2 = 0X80; // 关 闭 led
P2 = 0X00 ; P0 = 0X00 ; P2 = 0XA0; // 关 闭 led
}
**
**2 、 key.c
**
这里是独立按键,将板子左下方的J5的跳冒接到BTN模式
#include "key.h"
#define key_state0 0
#define key_state1 1
#define key_state2 2
unsigned char key_btn()
{
static char key_state = 0;
unsigned char key_press , key_return = 0 ;
if(P33 == 0) key_press = 0X07 ;
else if(P32 == 0) key_press = 0X0b ;
else if(P31 == 0) key_press = 0X0d ;
else if(P30 == 0) key_press = 0X0e ;
else key_press = 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 == 0x07)key_return = 4 ;
else if(key_press == 0x0b)key_return = 5 ;
else if(key_press == 0x0d)key_return = 6 ;
else if(key_press == 0x0e)key_return = 7 ;
key_state = key_state2 ;
}
else
{
key_state = key_state0 ;
}
break ;
case(key_state2):
if(key_press == 0x0f)
{
key_state = key_state0 ;
}
break ;
}
return key_return ;
}
**
**
**
3、iic.c
**
#include "iic.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;
}
unsigned char read_adc(unsigned char address)
{
unsigned char temp = 0 ;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(address);
IIC_WaitAck();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
temp = IIC_RecByte();
IIC_Stop();
return temp ;
}
void write_dac(unsigned char dat)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x40);
IIC_WaitAck();
IIC_SendByte(dat);
IIC_WaitAck();
IIC_Stop();
}
```4 、 头文件
iic.h
#ifndef _IIC_H
#define _IIC_H
#include "STC15F2K60S2.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);
*/
unsigned char read_adc(unsigned char address);
void write_dac(unsigned char dat);
#endif
key.h
#ifndef _KEY_H
#define _KEY_H
#include "STC15F2K60S2.H"
unsigned char key_btn();
#endif