很久没更新了,下周就要打国赛了,做一题练练手。
这套题还是很有难度的,个人感觉确实是跟省赛有很大的差距,主要的问题是中断和与函数的冲突问题需要解决,而且将各个模块的高程度糅合使复杂度上升了很高,而且因为需要使用PWM,而且是1khz的,因此对中断的响应要求也很严格。想了很久,我也没办法做到PWM高准确度的输出,下面的代码在PWM上大概周期有10%的误差,而且占空比也在10%左右进行跳变,如果有好的解决方法希望大佬指正。
示波器效果图
有问题的可以直接留言,我会尽力及时地回复,下面代码有强烈的个人风格,可能看懂也很困难,想要问某一部分怎么写欢迎直接留言问。
首先是main.c
#include <stc15f2k60s2.h>
#include <intrins.h>
#include "basic.h"
#include "iic.h"
void Timer0Init(void) //ne555计数器
{
TMOD |= 0x04; //设置定时器模式
TL0 = 0x00; //设置定时初值
TH0 = 0x00; //设置定时初值
TR0 = 0; //定时器0开始计时
}
void Timer1Init(void) //50毫秒@12.000MHz ne555计时器
{
AUXR &= 0xBF; //定时器时钟12T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0xB0; //设置定时初值
TH1 = 0x3C; //设置定时初值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
EA = 1;
ET1 = 1;
}
void Timer5Init(void) //100微秒@12.000MHz
{
AUXR &= 0xFB; //定时器时钟12T模式
T2L = 0x9C; //设置定时初值
T2H = 0xFF; //设置定时初值
AUXR |= 0x10; //定时器2开始计时
IE2 |= 0x04; //IE2 &= 0xfb;
}
unsigned int uine555,uivolt,uidistence;
// 单位百hz +5 单位% +10 单位10cm +1
unsigned char ucmod,uc50mscsb,uctimene555,ucadc,uccsmod,ucplcs = 90,ucsdcs = 40,ucjlcs = 6,ucplmod,uccjmod,uch5 = 0x00,uc100us,flagpwm,ucled,uch4 = 0xff,uc1ms,uc50msadc,uc50mskey;
unsigned char jdqdat;
bit flagne555;
sbit S4 = P3^3;sbit S5 = P3^2;sbit S6 = P3^1;sbit S7 = P3^0;
sbit TX = P1^0;sbit RX = P1^1;
bit flagS7;
void at24c02(unsigned char dat);
void replacene555();
void replacecsb();
void key();
void PCAinit();
void replacecsjm();
void ledcontrol();
void timer1() interrupt 3 //50ms的时基
{
uc50mscsb++;
uc50msadc++;
if(flagS7 == 1) //长按检测
{
uc50mskey++;
if(uc50mskey == 20)
{
jdqdat = 0;
uc50mskey = 0;
at24c02(0);
}
}
//上面为任务刷新率 下面是NE555
if(flagne555 == 1)
{
uctimene555++;
}
if(flagne555 == 0)
{
flagne555 = 1;
TH0 = 0;
TL0 = 0;
TR0 = 1;
}
else if(uctimene555 == 20)
{
TR0 = 0;
uine555 = (TH0 << 8) | TL0;
flagne555 = 0;
uctimene555 = 0;
}
}
bit flagpwm2;bit led4,led5,led6;
unsigned char temp138,tempP0;
void timer2() interrupt 12 //用于PWM
{
uc100us++;
if(uc100us == 10)
{
uc100us = 0;
uc1ms++;
}
switch(flagpwm)
{
case 0:
{
if(uc100us < 8 && flagpwm2 == 0)
{
hc138(0);
P0 = uch5;
P0 |= 0x20;
hc138(5);
hc138(0);
uch5 = P0;
flagpwm2 = 1;
}
else if(uc100us >=8 && flagpwm2 == 1)
{
hc138(0);
P0 = uch5;
P0 &= 0xdf;
hc138(5);
hc138(0);
uch5 = P0;
flagpwm2 = 0;
}
break;
}
case 1:
{
if(uc100us < 8 && flagpwm2 == 0)
{
hc138(0);
P0 = uch5;
P0 &= 0xdf;
hc138(5);
hc138(0);
uch5 = P0;
flagpwm2 = 1;
}
else if(uc100us >=8 && flagpwm2 == 1)
{
hc138(0);
P0 = uch5;
P0 |= 0x20;
hc138(5);
hc138(0);
uch5 = P0;
flagpwm2 = 0;
}
break;
}
}
ledcontrol(); //LED的闪烁与常亮控制
uc1ms %= 200;
}
void chaoshengbo()
{
unsigned char uccsbi; //超声波 使用PCA节约时钟
CH = 0xD8;
CL = 0xF0;
CF = 0;
RX = 1;
EA = 0;
for(uccsbi=0;uccsbi<=7;uccsbi++)
{
TX = 1;
Delay14us();
TX = 0;
Delay14us();
}
CR = 1;
while(CF == 0 && RX == 1)
{
}
CR = 0;
EA = 1;
if(RX == 0)
{
CH = CH - 0xD8;CL = CL - 0xF0;
uidistence = ((CH << 8) | CL) * 0.017;
}
else
{
uidistence = 000;
}
}
void adc()
{
IE2 &= 0xfb;
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(0x43);
I2CWaitAck();
I2CStop();
I2CStart();
I2CSendByte(0x91);
I2CWaitAck();
ucadc = I2CReceiveByte();
I2CSendAck(1);
I2CStop();
IE2 |= 0x04;
uivolt = ucadc * 100 / 255; //uivolt 直接转换成百分比形式
if(uivolt == 100)
{
uivolt = 99;
}
}
void dac()
{
unsigned char outvolt;
if(uivolt >= 80)
{
outvolt = 255;
}
else if(uivolt <=10)
{
outvolt = 51;
}
else
{
outvolt = 2.92 * uivolt + 21.8; //解函数
}
I2CStart();
I2CSendByte(0x90);
I2CWaitAck();
I2CSendByte(0x43);
I2CWaitAck();
I2CSendByte(outvolt);
I2CWaitAck();
I2CStop();
}
void smgled()
{
switch(ucmod)
{
case 0:
{
smgshow(1,15);
replacene555();
ucled = 1;
break;
}
case 1:
{
smgshow(1,16);
smgshow(7,uivolt / 10);
smgshow(8,uivolt % 10);
ucled = 2;
break;
}
case 2:
{
smgshow(1,10);
replacecsb();
ucled = 3;
break;
}
case 3:
{
smgshow(1,15);
replacecsjm();
ucled = 4;
break;
}
}
}
bit flagjdq;
void at24c02(unsigned char dat)
{
I2CStart();
I2CSendByte(0xa0);
I2CWaitAck();
I2CSendByte(0x00);
I2CWaitAck();
I2CSendByte(dat);
I2CWaitAck();
I2CStop();
}
void jdq()
{
if(uidistence >= ucjlcs * 10 && flagjdq == 0) //flagjdq用于不频繁对继电器进行切换
{
jdqdat++;
IE2 &= 0xfb;
at24c02(jdqdat);
hc138(0);
P0 = uch5;
P0 |= 0x10;
hc138(5);
hc138(0);
uch5 = P0;
IE2 |= 0x04;
flagjdq = 1;
}
else if(uidistence < ucjlcs * 10 && flagjdq == 1)
{
IE2 &= 0xfb;
hc138(0);
P0 = uch5;
P0 &= 0xef;
hc138(5);
hc138(0);
uch5 = P0;
IE2 |= 0x04;
flagjdq = 0;
}
}
void PWM() //flagpwm用于判断输出的类型
{
if(uine555 > ucplcs * 100)
{
flagpwm = 1;
}
else
{
flagpwm = 0;
}
}
void main()
{
flagne555 = 1;
init();
PCAinit();
Timer0Init();
Timer1Init();
Timer5Init();
Delay1000ms(); //开机延时
while(1)
{
key();
if(uc50msadc >= 4) //刷新率控制
{
adc();
dac();
uc50msadc = 0;
}
if(uc50mscsb >= 10) //刷新率控制
{
chaoshengbo();
uc50mscsb = 0;
}
PWM();
jdq();
smgled();
}
}
//||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||//
//下面是一些替代函数,就是为了缩短上面的行数来进行方便浏览用的
void ledcontrol() //小灯控制
{
switch(ucled)
{
case 1:
{
if(uc1ms == 0)
{
hc138(0);
P0 = uch4;
P0 = P0 | 0x07;
P0 = P0 & 0xfe;
hc138(4);
hc138(0);
uch4 = P0;
}
else if(uc1ms == 100)
{
hc138(0);
P0 = uch4;
P0 = P0 | 0x07;
P0 = P0 | 0x01;
hc138(4);
hc138(0);
uch4 = P0;
}
break;
}
case 2:
{
if(uc1ms == 0)
{
hc138(0);
P0 = uch4;
P0 = P0 | 0x07;
P0 = P0 & 0xfd;
hc138(4);
hc138(0);
uch4 = P0;
}
else if(uc1ms == 100)
{
hc138(0);
P0 = uch4;
P0 = P0 | 0x07;
P0 = P0 | 0x02;
hc138(4);
hc138(0);
uch4 = P0;
}
break;
}
case 3:
{
if(uc1ms == 0)
{
hc138(0);
P0 = uch4;
P0 = P0 | 0x07;
P0 = P0 & 0xfb;
hc138(4);
hc138(0);
uch4 = P0;
}
else if(uc1ms == 100)
{
hc138(0);
P0 = uch4;
P0 = P0 | 0x07;
P0 = P0 | 0x04;
hc138(4);
hc138(0);
uch4 = P0;
}
break;
}
default:
{
hc138(0);
P0 = uch4;
P0 = P0 | 0x07;
hc138(4);
hc138(0);
uch4 = P0;
}
}
if(uine555 > ucplcs * 100 && led4 == 0)
{
hc138(0);
P0 = uch4;
P0 = P0 & 0xf7;
hc138(4);
hc138(0);
uch4 = P0;
led4 = 1;
}
else
{
hc138(0);
P0 = uch4;
P0 = P0 | 0x08;
hc138(4);
hc138(0);
uch4 = P0;
led4 = 0;
}
if(uivolt > ucsdcs && led5 == 0)
{
hc138(0);
P0 = uch4;
P0 = P0 & 0xef;
hc138(4);
hc138(0);
uch4 = P0;
led5 = 1;
}
else
{
hc138(0);
P0 = uch4;
P0 = P0 | 0x10;
hc138(4);
hc138(0);
uch4 = P0;
led5 = 0;
}
if(uidistence > ucjlcs * 10 && led6 == 0)
{
hc138(0);
P0 = uch4;
P0 = P0 & 0xdf;
hc138(4);
hc138(0);
uch4 = P0;
led6 = 1;
}
else
{
hc138(0);
P0 = uch4;
P0 = P0 | 0x20;
hc138(4);
hc138(0);
uch4 = P0;
led6 = 0;
}
}
void replacemain() //放入按键延时里面 防止按键按下程序失效
{
if(uc50msadc >= 4)
{
adc();
dac();
uc50msadc = 0;
}
if(uc50mscsb >= 10)
{
chaoshengbo();
uc50mscsb = 0;
}
PWM();
jdq();
smgled();
}
void key() //按键扫描
{
S4 = 0;S5 = 0; S6 = 0;S7 = 0;
S4 = 1;
if(S4 == 0)
{
while(S4 == 0)
{
replacemain();
}
ucmod++;
ucmod %= 4;
uccsmod = 0;
Delay20ms();
}
S4 = 0;
S5 = 1;
if(S5 == 0)
{
while(S5 == 0)
{
replacemain();
}
if(ucmod == 3)
{
uccsmod++;
uccsmod %= 3;
}
Delay20ms();
}
S5 = 0;
S6 = 1;
if(S6 == 0)
{
while(S6 == 0)
{
replacemain();
}
if(ucmod == 3)
{
switch(uccsmod)
{
case 0:
{
ucplcs = ucplcs + 5;
if(ucplcs == 125)
{
ucplcs = 10;
}
break;
}
case 1:
{
ucsdcs = ucsdcs + 10;
if(ucsdcs == 70)
{
ucsdcs = 10;
}
break;
}
case 2:
{
ucjlcs = ucjlcs + 1;
if(ucjlcs == 13)
{
ucjlcs = 1;
}
break;
}
}
}
else if(ucmod == 2)
{
uccjmod++;
uccjmod %= 2;
}
Delay20ms();
}
S6 = 0;
S7 = 1;
if(S7 == 0)
{
uc50mskey = 0;
flagS7 = 1;
while(S7 == 0)
{
replacemain();
}
flagS7 = 0;
if(ucmod == 3)
{
switch(uccsmod)
{
case 0:
{
ucplcs = ucplcs - 5;
if(ucplcs == 5)
{
ucplcs = 120;
}
break;
}
case 1:
{
ucsdcs = ucsdcs - 10;
if(ucsdcs == 0)
{
ucsdcs = 60;
}
break;
}
case 2:
{
ucjlcs = ucjlcs - 1;
if(ucjlcs == 0)
{
ucjlcs = 12;
}
break;
}
}
}
else if(ucmod == 0)
{
ucplmod++;
ucplmod %= 2;
}
Delay20ms();
}
S7 = 0;
}
void PCAinit() //PCA的初始化
{
CMOD = 0x00;
CCON = 0x00;
CL = 0;
CH = 0;
}
void replacecsjm() //参数界面
{
switch(uccsmod)
{
case 0:
{
smgshow(2,1);
if(ucplcs / 100 > 0)
{
smgshow(6,ucplcs / 100);
smgshowdot(7,ucplcs / 10 % 10);
smgshow(8,ucplcs % 10);
}
else
{
smgshowdot(7,ucplcs / 10 % 10);
smgshow(8,ucplcs % 10);
}
break;
}
case 1:
{
smgshow(2,2);
smgshow(7,ucsdcs / 10);
smgshow(8,ucsdcs % 10);
break;
}
case 2:
{
smgshow(2,3);
smgshowdot(7,ucjlcs / 10);
smgshow(8,ucjlcs % 10);
break;
}
}
}
void replacecsb() //超声波界面
{
switch(uccjmod)
{
case 0:
{
if(uidistence / 100 > 0)
{
smgshow(6,uidistence / 100);
smgshow(7,uidistence / 10 % 10);
smgshow(8,uidistence % 10);
}
else if(uidistence / 10 % 10 > 0)
{
smgshow(7,uidistence / 10 % 10);
smgshow(8,uidistence % 10);
}
else if(uidistence % 10)
{
smgshow(8,uidistence % 10);
}
break;
}
case 1:
{
smgshowdot(6,uidistence / 100);
smgshow(7,uidistence / 10 % 10);
smgshow(8,uidistence % 10);
break;
}
}
}
void replacene555() //ne555界面
{
unsigned int lsne555;
switch(ucplmod)
{
case 0:
{
if(uine555 / 100000 > 0)
{
smgshow(3,uine555 / 100000);
smgshow(4,uine555 / 10000 % 10);
smgshow(5,uine555 / 1000 % 10);
smgshow(6,uine555 / 100 % 10);
smgshow(7,uine555 / 10 % 10);
smgshow(8,uine555 % 10);
}
else if(uine555 / 10000 % 10 > 0)
{
smgshow(4,uine555 / 10000 % 10);
smgshow(5,uine555 / 1000 % 10);
smgshow(6,uine555 / 100 % 10);
smgshow(7,uine555 / 10 % 10);
smgshow(8,uine555 % 10);
}
else if(uine555 / 1000 % 10 > 0)
{
smgshow(5,uine555 / 1000 % 10);
smgshow(6,uine555 / 100 % 10);
smgshow(7,uine555 / 10 % 10);
smgshow(8,uine555 % 10);
}
else if(uine555 / 100 % 10 > 0)
{
smgshow(6,uine555 / 100 % 10);
smgshow(7,uine555 / 10 % 10);
smgshow(8,uine555 % 10);
}
else if(uine555 / 10 % 10 > 0)
{
smgshow(7,uine555 / 10 % 10);
smgshow(8,uine555 % 10);
}
else if(uine555 % 10 > 0)
{
smgshow(8,uine555 % 10);
}
break;
}
case 1:
{
lsne555 = uine555 / 100;
if(lsne555 / 100000 > 0)
{
smgshow(3,lsne555 / 100000);
smgshow(4,lsne555 / 10000 % 10);
smgshow(5,lsne555 / 1000 % 10);
smgshow(6,lsne555 / 100 % 10);
smgshowdot(7,lsne555 / 10 % 10);
smgshow(8,lsne555 % 10);
}
else if(lsne555 / 10000 % 10 > 0)
{
smgshow(4,lsne555 / 10000 % 10);
smgshow(5,lsne555 / 1000 % 10);
smgshow(6,lsne555 / 100 % 10);
smgshowdot(7,lsne555 / 10 % 10);
smgshow(8,lsne555 % 10);
}
else if(lsne555 / 1000 % 10 > 0)
{
smgshow(5,lsne555 / 1000 % 10);
smgshow(6,lsne555 / 100 % 10);
smgshowdot(7,lsne555 / 10 % 10);
smgshow(8,lsne555 % 10);
}
else if(lsne555 / 100 % 10 > 0)
{
smgshow(6,lsne555 / 100 % 10);
smgshowdot(7,lsne555 / 10 % 10);
smgshow(8,lsne555 % 10);
}
else if(lsne555 / 10 % 10 > 0)
{
smgshowdot(7,lsne555 / 10 % 10);
smgshow(8,lsne555 % 10);
}
else if(lsne555 % 10 > 0)
{
smgshowdot(7,0);
smgshow(8,lsne555 % 10);
}
break;
}
}
}
basic.c主要用于一些延时函数的存放,和数码管显示
#include "basic.h"
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
0x89 //H
};
void Delay14us() //@12.000MHz
{
unsigned char i;
_nop_();
_nop_();
i = 39;
while (--i);
}
unsigned char uc138;
void hc138(unsigned char hc138k)
{
switch(hc138k)
{
case 0:
{
P2 = (P2 & 0x1f) | 0x00;
break;
}
case 4:
{
P2 = (P2 & 0x1f) | 0x80;
break;
}
case 5:
{
P2 = (P2 & 0x1f) | 0xa0;
break;
}
case 6:
{
P2 = (P2 & 0x1f) | 0xc0;
break;
}
case 7:
{
P2 = (P2 & 0x1f) | 0xe0;
break;
}
}
}
void Delay200us() //@12.000MHz
{
unsigned char i, j;
i = 3;
j = 82;
do
{
while (--j);
} while (--i);
}
void Delay1000ms() //@12.000MHz
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 46;
j = 153;
k = 245;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
void smgshow(unsigned char smgwei,smgduan)
{
IE2 &= 0xfb;
hc138(0);
P0 = 0x01 << (smgwei - 1);
hc138(6);
hc138(0);
P0 = Seg_Table[smgduan];
hc138(7);
hc138(0);
IE2 |= 0x04;
Delay200us();
IE2 &= 0xfb;
hc138(7);
P0 = 0xff;
hc138(0);
IE2 |= 0x04;
}
void smgshowdot(unsigned char smgwei,smgduan)
{
IE2 &= 0xfb;
hc138(0);
P0 = 0x01 << (smgwei - 1);
hc138(6);
hc138(0);
P0 = Seg_Table[smgduan] & 0x7f;
hc138(7);
hc138(0);
IE2 |= 0x04;
Delay200us();
IE2 &= 0xfb;
hc138(7);
P0 = 0xff;
hc138(0);
IE2 |= 0x04;
}
void init()
{
hc138(4);
P0 = 0xff;
hc138(7);
P0 = 0xff;
hc138(6);
P0 = 0x00;
hc138(5);
P0 = 0x00;
hc138(0);
}
void Delay20ms() //@12.000MHz
{
unsigned char i, j, k;
_nop_();
_nop_();
i = 1;
j = 234;
k = 113;
do
{
do
{
while (--k);
} while (--j);
} while (--i);
}
basic.h
#ifndef __BASIC_H_
#define __BASIC_H_
#include <stc15f2k60s2.h>
#include <intrins.h>
void smgshow(unsigned char smgwei,smgduan);
void smgshowdot(unsigned char smgwei,smgduan);
void hc138(unsigned char hc138k);
void Delay1000ms(void);
void Delay20ms();
void Delay14us();
void init();
#endif
iic.c
#include <intrins.h>
#include <stc15f2k60s2.h>
#define DELAY_TIME 5
sbit scl = P2^0;
sbit sda = P2^1;
//
static void I2C_Delay(unsigned char n)
{
do
{
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
_nop_();_nop_();_nop_();_nop_();_nop_();
}
while(n--);
}
//
void I2CStart(void)
{
sda = 1;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 0;
I2C_Delay(DELAY_TIME);
scl = 0;
}
//
void I2CStop(void)
{
sda = 0;
scl = 1;
I2C_Delay(DELAY_TIME);
sda = 1;
I2C_Delay(DELAY_TIME);
}
//
void I2CSendByte(unsigned char byt)
{
unsigned char i;
for(i=0; i<8; i++){
scl = 0;
I2C_Delay(DELAY_TIME);
if(byt & 0x80){
sda = 1;
}
else{
sda = 0;
}
I2C_Delay(DELAY_TIME);
scl = 1;
byt <<= 1;
I2C_Delay(DELAY_TIME);
}
scl = 0;
}
//
unsigned char I2CReceiveByte(void)
{
unsigned char da;
unsigned char i;
for(i=0;i<8;i++){
scl = 1;
I2C_Delay(DELAY_TIME);
da <<= 1;
if(sda)
da |= 0x01;
scl = 0;
I2C_Delay(DELAY_TIME);
}
return da;
}
//
unsigned char I2CWaitAck(void)
{
unsigned char ackbit;
scl = 1;
I2C_Delay(DELAY_TIME);
ackbit = sda;
scl = 0;
I2C_Delay(DELAY_TIME);
return ackbit;
}
//
void I2CSendAck(unsigned char ackbit)
{
scl = 0;
sda = ackbit;
I2C_Delay(DELAY_TIME);
scl = 1;
I2C_Delay(DELAY_TIME);
scl = 0;
sda = 1;
I2C_Delay(DELAY_TIME);
}
iic.h
#ifndef _IIC_H_
#define _IIC_H_
void I2CStart(void);
void I2CStop(void);
void I2CSendByte(unsigned char byt);
unsigned char I2CReceiveByte(void);
unsigned char I2CWaitAck(void);
void I2CSendAck(unsigned char ackbit);
#endif