前言:比赛一天天接近,十分紧张,有没有大佬可以分享一下数模电的速成资源,有偿求
题目
个人理解与感受
第十二届国赛的题目难度也中规中矩,毕竟分值没有14届的高,况且还少考了单总线温度传感器的使用,依旧没有考串口。这道题目写起来没有什么太大的阻碍,连续采样功能我有印象有省赛考过,连续采样六次的,好像是第十四届的省赛,光敏传感器触发第十四届也“回光返照”过,也不是什么新鲜的考点了。本次一个稍微新颖但是没有难度的一个地方就是是根据DS1302中的秒值来进行读取,这实质上也是考察BCD码与十进制码的转换,与第十一届的题目类似。
关于多次采样计算平均值,我是直接用一个long来计算之前所有的总和,这样需要的空间就比较固定,也不会有溢出的风险,代码量也相当少:
disall = disall + distance;
if(trigger > 0){
disavr = disall * 10 / trigger;
}
其中disall就是long类型的用于承载之前所有距离的变量,trigger是测试的次数,将disall先×10是为了搞到小数点,也不用浮点型的变量,非常非常方便好用。
当然用数组的方法也是可以,但是代码量会比较多,排序也比较麻烦,而且占用空间比较大。
LED模块我依旧使用先给状态量赋值再给P0赋值的方法来点亮LED灯,效果很稳定。
关于DAC的变量,我的建议是用斜率-截距式的表达式进行赋值,两点式和点斜式很好写,但是用整形来写容易失真。
截距式更不用说了,纯纯自虐。
底层驱动代码
IIC
unsigned char guangmin(){
unsigned char ret;
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(0x41);
I2CWaitAck();
I2CStart();
I2CSendByte(0x91);
I2CWaitAck();
ret = I2CReceiveByte();
I2CSendAck(1);
I2CStop();
return ret;
}
void DAC(unsigned char dat){
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(0x41);
I2CWaitAck();
I2CSendByte(dat);
I2CWaitAck();
I2CStop();
}
DS1302
调用部分写在了主函数
void ds1302config(){
unsigned char i;
Write_Ds1302_Byte(0x8e,0x00);
for(i = 0;i < 3;i++){
Write_Ds1302_Byte(ds1302writeaddr[i],time[i]);
}
Write_Ds1302_Byte(0x8e,0x80);
}
void ds1302read(){
unsigned char i;
for(i = 0;i < 3;i++){
time[i] = Read_Ds1302_Byte(ds1302readaddr[i]);
}
secondtmp = (time[0] / 16 * 10) + (time[0] % 16);
}
主程序代码
#include <STC15F2K60S2.H>
#include "inithc138.h"
#include "delay.h"
#include "ds1302.h"
#include "intrins.h"
#include "iic.h"
#define de 5
code unsigned char Seg_Table[17] =
{
0xc0, //0
0xf9, //1
0xa4, //2
0xb0, //3
0x99, //4
0x92, //5
0x82, //6
0xf8, //7
0x80, //8
0x90, //9
0x88, //A
0x83, //b
0xc6, //C
0xa1, //d
0x86, //E
0x8e, //F
0xbf
};
unsigned char ds1302readaddr[3] = {0x81,0x83,0x85};
unsigned char ds1302writeaddr[3] = {0x80,0x82,0x84};
unsigned char time[3] = {0x01,0x20,0x20};
unsigned char mode1 = 0;
unsigned char mode2 = 0;
bit moshi = 0;//模式标识符
unsigned char jilu = 0;//记录模式选择
unsigned int ustime = 0;//超声波时间
unsigned int distance = 0;//超声波距离
unsigned int dismax = 0;//最大距离
unsigned long disall = 0;//距离总和
unsigned long disavr = 0;//平均距离
unsigned int dismin = 0;//最小距离
unsigned char trigger = 0;//采集次数
unsigned char caijishijian = 2;//采集时间
unsigned char julicanshu = 20;//距离参数
bit show = 0;//显示模式选择
unsigned char voltage = 0;//光敏电阻电压数据
bit light = 0;//亮暗状态
unsigned char secondtmp = 0;
unsigned char ledstat = 0xff;//LED状态
unsigned char dacload = 0;//DAC输出量
bit flag = 0;//保证每次进入测距状态只测一次
unsigned char canshufujin = 0;//记录距离在定时模式下位于参数附近的次数
//***********************************DS1302
void ds1302config(){
unsigned char i;
Write_Ds1302_Byte(0x8e,0x00);
for(i = 0;i < 3;i++){
Write_Ds1302_Byte(ds1302writeaddr[i],time[i]);
}
Write_Ds1302_Byte(0x8e,0x80);
}
void ds1302read(){
unsigned char i;
for(i = 0;i < 3;i++){
time[i] = Read_Ds1302_Byte(ds1302readaddr[i]);
}
secondtmp = (time[0] / 16 * 10) + (time[0] % 16);
}
//***********************************
//***********************************超声波
sbit TX = P1^0;
sbit RX = P1^1;
void Delay12us(void) //@12.000MHz
{
unsigned char data i;
_nop_();
_nop_();
i = 33;
while (--i);
}
void fangbo(){
unsigned char i;
for(i = 0;i < 8;i++){
TX = 1;
Delay12us();
TX = 0;
Delay12us();
}
}
void ceju(){
flag = 1;//测了
CMOD = 0x00; //设置定时器模式
CL = 0x00; //设置定时初始值
CH = 0x00; //设置定时初始值
CF = 0; //清除TF0标志
CR = 0;
fangbo();
CR = 1;
while((RX == 1) && (CH < 0x17));
CR = 0;
if(RX == 0){
RX = 1;
ustime = (CH << 8) | CL;
distance = ustime * 0.017;
}
}
//***********************************
//***********************************数据显示界面
void shijianshuju(){//时间数据显示界面
showsmg(1,Seg_Table[time[2] / 16]);
showsmg(2,Seg_Table[time[2] % 16]);
showsmg(3,Seg_Table[16]);
showsmg(4,Seg_Table[time[1] / 16]);
showsmg(5,Seg_Table[time[1] % 16]);
showsmg(6,Seg_Table[16]);
showsmg(7,Seg_Table[time[0] / 16]);
showsmg(8,Seg_Table[time[0] % 16]);
}
void julishuju(){//距离记录
showsmg(1,0xc7);
if(moshi == 0){
showsmg(2,Seg_Table[12]);//触发模式
}else{
showsmg(2,Seg_Table[15]);//定时模式
}
showsmg(8,Seg_Table[distance % 10]);
if(distance > 9){
showsmg(7,Seg_Table[distance / 10 % 10]);
}
if(distance > 99){
showsmg(6,Seg_Table[distance / 100]);
}
}
void shujujilu(){
if(jilu == 0){
showsmg(1,0x89);
showsmg(2,0xfe);
showsmg(7,Seg_Table[dismax / 10]);
showsmg(8,Seg_Table[dismax % 10]);
}
if(jilu == 1){
showsmg(1,0x89);
showsmg(2,0xbf);
showsmg(6,Seg_Table[disavr / 100]);
showsmg(7,Seg_Table[disavr / 10 % 10] & 0x7f);
showsmg(8,Seg_Table[disavr % 10]);
}
if(jilu == 2){
showsmg(1,0x89);
showsmg(2,0xf7);
showsmg(7,Seg_Table[dismin / 10]);
showsmg(8,Seg_Table[dismin % 10]);
}
}
void xianshi(){
switch(mode1){
case 0:shijianshuju();break;
case 1:julishuju();break;
case 2:shujujilu();break;
}
}
//***********************************
//***********************************参数设置界面
void caijishijianshezhi(){//采集时间设置界面
showsmg(1,0x8c);
showsmg(2,Seg_Table[1]);
showsmg(7,Seg_Table[caijishijian / 10]);
showsmg(8,Seg_Table[caijishijian % 10]);
}
void julicanshushezhi(){//距离参数设置界面
showsmg(1,0x8c);
showsmg(2,Seg_Table[2]);
showsmg(7,Seg_Table[julicanshu / 10]);
showsmg(8,Seg_Table[julicanshu % 10]);
}
void canshujiemian(){
switch(mode2){
case 0:caijishijianshezhi();break;
case 1:julicanshushezhi();break;
}
}
//***********************************
//***********************************
void showselect(){
if(show == 0){
xianshi();//数据显示界面
}else{
canshujiemian();//参数设置界面
}
}
//***********************************
//***********************************按键扫描
void scankey(){
P33 = 0;P32 = 1;P44 = 1;P35 = 1;
if(P44 == 0){Delay(de);while(P44 == 0){showselect();}//S4
show = ~show;
mode1 = 0;mode2 = 0;jilu = 0;
}
if((show == 0) && (mode1 == 1)){//S13在测距数据显示界面下
if(P35 == 0){Delay(de);while(P35 == 0){showselect();}
moshi = ~moshi;
}
}
if((show == 0) && (mode1 == 2)){//S13在数据记录显示界面下
if(P35 == 0){Delay(de);while(P35 == 0){showselect();}
jilu++;
jilu %= 3;
}
}
P33 = 1;P32 = 0;P44 = 1;P35 = 1;
if(show == 0){//S5在数据显示界面下
if(P44 == 0){Delay(de);while(P44 == 0){showselect();}
mode1++;
mode1 %= 3;
}
}
if(show == 1){//S5在参数设置界面下
if(P44 == 0){Delay(de);while(P44 == 0){showselect();}
mode2++;
mode2 %= 2;
}
}
if(P35 == 0){Delay(de);while(P35 == 0){showselect();}//S4}
if(show == 1){//S13为参数调整按键
if(mode2 == 0){//调整采集时间参数
caijishijian++;
if(caijishijian > 9){caijishijian = 2;}
}
if(mode2 == 1){//调整距离参数
julicanshu += 10;
if(julicanshu > 80){julicanshu = 10;}
}
}
}
}
//***********************************
//***********************************测距模式
void jilumoshi(){//记录数据判断
if(trigger == 1){//最小值的初始化
dismin = distance;
}
if(dismax < distance){//记录最大值
dismax = distance;
}
if(dismin > distance){
dismin = distance;
}
disall = disall + distance;
if(trigger > 0){
disavr = disall * 10 / trigger;
}
if(moshi == 1){
if((distance >= (julicanshu - 5)) && (distance <= julicanshu + 5)){
canshufujin++;
}else{
canshufujin = 0;
}
}else{
canshufujin = 0;
}
}
void lianganpanduan(){
voltage = guangmin();
Delay(1);
if(voltage < 20){
light = 1;//暗下来
}else{
light = 0;//亮
}
}
void dingshimoshi(){//定时模式
if(secondtmp % caijishijian == 0){
if(flag == 0){
ceju();
trigger++;
jilumoshi();
}
}else{
flag = 0;
}
}
void chufamoshi(){//触发模式
if(light == 1){
if(flag == 0){
ceju();
trigger++;
jilumoshi();
}
}else{
flag = 0;
}
}
void cejumoshi(){
if(moshi == 0){
chufamoshi();
}
if(moshi == 1){
dingshimoshi();
}
}
//***********************************
//***********************************LED
void led(){
if((show == 0) && (mode1 == 0)){
ledstat = ledstat & ~0x01;
}else{
ledstat = ledstat | 0x01;
}
if((show == 0) && (mode1 == 1)){
ledstat = ledstat & ~0x02;
}else{
ledstat = ledstat | 0x02;
}
if((show == 0) && (mode1 == 2)){
ledstat = ledstat & ~0x04;
}else{
ledstat = ledstat | 0x04;
}
if(moshi == 0){//触发模式
ledstat = ledstat & ~0x08;
}else{
ledstat = ledstat | 0x08;
}
if(canshufujin >= 3){//定时模式下附近次数超过三次
ledstat = ledstat & ~0x10;
}else{
ledstat = ledstat | 0x10;
}
if(light){
ledstat = ledstat | 0x20;
}else{
ledstat = ledstat & ~0x20;
}
outputp0(4,ledstat);
}
//***********************************
//***********************************
void DACshuchu(){
if(distance <= 10){
dacload = 51;
}else if(distance >= 80){
dacload = 255;
}else{
dacload = 2.91 * distance + 21.86;
}
DAC(dacload);
Delay(1);
}
//***********************************
//***********************************
void main(){
initsys();
ds1302config();
ds1302read();
lianganpanduan();
Delay(5);
initsys();
while(1){
lianganpanduan();
cejumoshi();
ds1302read();
showselect();
scankey();
led();
DACshuchu();
}
}
展示视频
注:一个人拍视频旁边没支架,DAC就没法展示了,但是是可以实现的。
我的板子s8不行,我就把功能换成了s12和s13。
g012