2019年5月22日更新
因为我当时读错了题,没有在程序中写DA的程序,现在把DA的程序放在下面,主程序里面调用就可以了,我就不改了
void SetDACOut(unsigned char val)
{
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(0x40);
IIC_WaitAck();
IIC_SendByte(val);
IIC_WaitAck();
IIC_Stop();
}
2019年3月26日更新
重新审了一下题目要求,好的,最基础的错误审题错误,没有理会出题人意思。
1、电压测量显示模式下就一直显示RB2的输出电压,不会随着S5的按下而锁定为2.0V
2、S5改变的是DAC输出,还是要写DAC输出,S5决定DAC的输出是否锁定。
代码就懒得改了
就这水平还想着进国赛,脑子有泡吧!专心考研吧孩子。
ok,蓝桥第一阶段告一段落,看一个月后能不能进国赛再说了。
emmmm,忘了备份试题pdf......
那就完全靠回忆吧。
需要使用AD模块、数码管、LED、NE555以及独立按键。
其实我拿到这个题后,一看笑了,使用NE555测频,不就是第七届国赛题吗,而且官方在赛前以及在官网放了这个模拟题,我正好就写了这个题(滑稽)。参考 https://blog.csdn.net/Xiaomo_haa/article/details/88597373
但是又一看,DAC,我他妈,我还没调试过这个东西啊,当时就懵逼了,但是再一看,什么鬼DAC,还是AD。
那么,这个题就很有意思了,非常简单了。
NE555测频原理
很多人不知道NE555测频怎么搞,其实很简单。
已经使用跳线帽将P34和NE555的输出端接在一起了,关乎NE555,有些许数电基础的都明白,NE555就是改变RB3,改变负载电阻,使其输出方波的频率发生改变,其中并不涉及任何对NE555的编程,当然你也没法对其编程。
官方的CT107D的NE555输出频率范围是50-20K赫兹(以上)。
那么我们怎么测频呢。
P34对应的是单片机的定时器0的脉冲输入口,那么我们可以把定时器0设置为计数模式,每接收到NE555的一个脉冲,定时器0计数值就加1,然后500ms读取一次定时器0的计数值,再乘以2大约就是1s内的脉冲,不就是NE555输出的方波的频率吗。
然后按键、LED、数码管等等其余需要使用定时器的就使用定时器1来完成。
这个题真的很简单,一小时多一点点搞定。
注释写的应该够详细了,凑合看吧。
main.c
#include "sys.h"
bit flag200ms = 0, flag500ms = 0;
bit flagval = 0, flagled = 1, flagtube = 1;
unsigned char mode = 2;
unsigned int FRE, VAL;
unsigned char LEDDAT = 0xff, led = 0xff;
void main(void)
{
All_Init();
Timer1Init();
Timer0Init();
EA = 1;
while(1)
{
//200ma读取一次AD
if(flag200ms)
{
flag200ms = 0;
VAL = Read_AIN(0x03); //读取AIN3的数据
}
//500ms测频一次
if(flag500ms)
{
flag500ms = 0;
TR0 = 0; //关闭定时器0计数
FRE = TH0 * 256 + TL0; //统计500ms内脉冲数
FRE *= 2; //乘以2就是1s内脉冲数,就是频率
TH0 = TL0 = 0; //清除定时器0计数数据
TR0 = 1; //定时器0重新开始计数
}
//如果S5按下,val就是固定的2.0V
if(flagval == 0)
VAL = 200;
//如果LED显示打开
if(flagled)
{
switch(mode)
{
case 1: LEDDAT = (LEDDAT | 0x03) & 0xfd; break; //模式1为测频模式
case 2: LEDDAT = (LEDDAT | 0x03) & 0xfe; break; //模式2为测电压模式
}
//如果是测频模式,根据范围选择点亮LED
if(mode == 1)
{
LEDDAT = LEDDAT | 0x10; //关闭L5
LEDDAT = LEDDAT | 0x04; //关闭L3
if(FRE < 1000)
LEDDAT = LEDDAT | 0x08; //关闭L4
else if((FRE >= 1000) && (FRE < 5000))
LEDDAT = (LEDDAT | 0x08) & 0xf7; //打开L4
else if((FRE >= 5000) && (FRE < 10000))
LEDDAT = LEDDAT | 0x08; //关闭L4
else if(FRE > 10000)
LEDDAT = (LEDDAT | 0x08) & 0xf7; //打开L4
}
//如果是测电压模式,根据电压范围选择点亮LED
else if(mode == 2)
{
//不是固定输出2.0V状态
if(flagval)
{
LEDDAT = LEDDAT & 0xef; //打开L5
LEDDAT = LEDDAT | 0x08; //关闭L4
if(VAL < 150)
LEDDAT = LEDDAT | 0x04; //关闭L3
else if((VAL >= 150) && (VAL < 250))
LEDDAT = (LEDDAT | 0x04) & 0xfb; //打开L3
else if((VAL > 250) && (VAL < 350))
LEDDAT = LEDDAT | 0x04; //关闭L3
else if(VAL > 350)
LEDDAT = (LEDDAT | 0x04) & 0xfb; //打开L3
}
//固定输出2.0V状态
else
{
LEDDAT = LEDDAT | 0x10; //关闭L5
LEDDAT = LEDDAT | 0x04; //关闭L3
}
}
}
//LED关闭状态,LED全灭
else
LEDDAT = 0xff;
led = LEDDAT;
KeyPress();
TubeScan();
}
}
sys.c
#include "sys.h"
void All_Init(void)
{
P2 = (P2 & 0x1f) | 0x80;
P0 = 0xff;
P2 = (P2 & 0x1f) | 0xe0;
P0 = 0xff;
P2 = (P2 & 0x1f) | 0xa0;
P0 = 0x00;
P2 = P2 & 0x1f;
}
//定时器1初始化
void Timer1Init(void) //2毫秒@12.000MHz
{
AUXR &= 0xBF; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x30; //设置定时初值
TH1 = 0xF8; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
ET1 = 1;
}
//定时器1中断服务程序
void Timer1(void) interrupt 3
{
static unsigned char t00 = 0, t01 = 0;
t00 ++; //200ms
t01 ++; //500ms
if(t00 >= 100)
{
t00 = 0;
flag200ms = 1;
}
if(t01 >= 250)
{
t01 = 0;
flag500ms = 1;
}
LedLight();
KeyScan();
TubeShow();
}
//定时器0初始化为计数模式
void Timer0Init(void)
{
AUXR &= 0x7F; //定时器时钟12T模式
TMOD = 0x04; //设置定时器0为16位自动重装载外部记数模式
TH0 = TL0 = 0; //设置定时器0初始值
TR0 = 1; //定时器0开始工作
}
sys.h
#ifndef _SYS_H_
#define _SYS_H_
#include
#include
#include "iic.h"
sbit S7 = P3^0;
sbit S6 = P3^1;
sbit S5 = P3^2;
sbit S4 = P3^3;
extern bit flag200ms, flag500ms;
extern bit flagval, flagled, flagtube;
extern unsigned char mode; //mode=为测频模式, mode =2为测电压模式
extern unsigned int FRE, VAL;
extern unsigned char LEDDAT, led;
void All_Init(void);
void Timer1Init(void);
void Timer0Init(void);
void KeyScan(void);
void KeyPress(void);
void KeyAction(unsigned char key);
void TubeScan(void);
void TubeShow(void);
void LedLight(void);
#endif
display.c
#include "sys.h"
unsigned char code table[]={0xc0, 0xf9, 0xa4, 0xb0, 0x99, 0x92, 0x82, 0xf8,
0x80, 0x90, 0x88, 0x83, 0xc6, 0xa1, 0x86, 0x8e,
0xff, 0xbf, 0xc1};
unsigned char TubeBuff[] = {0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff, 0xff};
unsigned char smg1, smg2, smg3, smg4, smg5, smg6, smg7, smg8;
void TubeShow(void)
{
static unsigned char index = 0;
P0 = 0x00;
P2 = (P2 & 0x1f) | 0xc0;
P0 = 0x01 << index;
P2 = P2 & 0x1f;
P0 = 0xff;
P2 = (P2 & 0x1f) | 0xe0;
P0 = TubeBuff[index];
P2 = P2 & 0x1f;
index ++;
index &= 0x07;
}
void TubeScan(void)
{
//如果为测频显示,这样显示
if(mode == 1)
{
smg1 = 15; //显示F
smg2 =smg3 = 16; //熄灭
smg4 = FRE / 10000;
smg5 = (FRE % 10000) / 1000;
smg6 = (FRE % 1000) / 100;
smg7 = (FRE % 100) / 10;
smg8 = FRE % 10;
//消0
if(smg4 == 0)
{
smg4 = 16;
if(smg5 == 0)
{
smg5 = 16;
if(smg6 == 0)
{
smg6 = 16;
if(smg7 == 0)
{
smg7 = 16;
}
}
}
}
}
//如果是测电压模式
else if(mode == 2)
{
smg1 = 18; //显示U
smg2 = smg3 = smg4 = smg5 = 16; //熄灭
smg6 = VAL / 100;
smg7 = (VAL % 100) / 10;
smg8 = VAL % 10;
}
//如果关闭数码管时全部熄灭
if(flagtube == 0)
smg1 = smg2 = smg3 = smg4 = smg5 = smg6 = smg7 = smg8 = 16;
if((mode == 2) && (flagtube == 1))
TubeBuff[5] = table[smg6] & 0x7f; //测电压时加上小数点
else
TubeBuff[5] = table[smg6];
TubeBuff[0] = table[smg1];
TubeBuff[1] = table[smg2];
TubeBuff[2] = table[smg3];
TubeBuff[3] = table[smg4];
TubeBuff[4] = table[smg5];
TubeBuff[6] = table[smg7];
TubeBuff[7] = table[smg8];
}
void LedLight(void)
{
P0 = 0xff;
P2 = (P2 & 0x1f) | 0x80;
P0 = led;
P2 = P2 & 0x1f;
}
key.c
#include "sys.h"
unsigned char keysta[] = {1, 1, 1, 1};
unsigned char keybackup[] = {1, 1, 1, 1};
unsigned char keybuff[] = {0xff, 0xff, 0xff, 0xff};
void KeyScan(void)
{
unsigned char i;
keybuff[0] = (keybuff[0] << 1) | S4;
keybuff[1] = (keybuff[1] << 1) | S5;
keybuff[2] = (keybuff[2] << 1) | S6;
keybuff[3] = (keybuff[3] << 1) | S7;
for(i = 0; i < 4; i ++)
{
if(keybuff[i] == 0xff)
keysta[i] = 1;
else if(keybuff[i] == 0x00)
keysta[i] = 0;
}
}
void KeyPress(void)
{
unsigned char i;
for(i = 0; i < 4; i ++)
{
if(keysta[i] != keybackup[i])
{
if(keysta[i] == 0)
KeyAction(i);
keybackup[i] = keysta[i];
}
}
}
void KeyAction(unsigned char key)
{
//S4按键切换测频和测电压模式
if(key == 0)
{
if(mode == 1) //如果是模式就切换到模式2
mode = 2;
else if(mode == 2) //如果是模式2就切换到模式
mode = 1;
}
//S5为是否为固定输出2.0V
else if(key == 1)
flagval = !flagval;
//S6控制是否打开LED
else if(key == 2)
flagled = ~flagled;
//S7控制是否打开数码管显示
else if(key == 3) //S7
flagtube = !flagtube;
}
iic.c
#include "sys.h"
#define somenop {_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();_nop_();}
sbit SDA = P2^1; /* 数据线 */
sbit SCL = P2^0; /* 时钟线 */
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;
}
void IIC_Ack(bit ackbit)
{
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 = 0;
IIC_Stop();
return 0;
}
else
{
SCL = 0;
return 1;
}
}
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;
}
}
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 int Read_AIN(unsigned char chn)
{
unsigned int temp_val;
unsigned char dat;
IIC_Start();
IIC_SendByte(0x90);
IIC_WaitAck();
IIC_SendByte(chn);
IIC_WaitAck();
IIC_Stop();
IIC_Start();
IIC_SendByte(0x91);
IIC_WaitAck();
dat = IIC_RecByte();
IIC_Ack(0);
IIC_Stop();
temp_val = ((unsigned int)(dat) * (50000 / 255));
temp_val /= 100;
return temp_val;
}
iic.h
#ifndef _IIC_H
#define _IIC_H
void IIC_Start(void);
void IIC_Stop(void);
void IIC_Ack(bit ackbit);
void IIC_SendByte(unsigned char byt);
bit IIC_WaitAck(void);
unsigned char IIC_RecByte(void);
unsigned int Read_AIN(unsigned char chn);
void Write_E2PROM(unsigned char add, unsigned char dat);
unsigned char Read_E2PROM(unsigned char add);
#endif