写在前面:做完总体来说感觉一年比一年难了(估计是被骂的),虽然十三届用的底层少,但是做起来困难重重。
最难的难点在于定时器安排问题。15F2K60S2系列单片机只有三个定时器,本届题目考到了频率测量、超声波、PWM输出,再加上刷新,每一个都需要一个定时器,比较简单的做法之一是直接用单片机外设PCA来检测超声波,节省定时器资源。(b站上有个up主是切换定时器0计数/定时模式来实现的,这样也可以,但是个人感觉比较麻烦,也容易出现问题)
对于NE555频率测量,要求是P3^4进行脉冲输入,正好是T0输出,所以最好是用定时器0,当然也可以使用其它定时器,这样就需要使用sbit函数定义P3^4引脚,相对比较麻烦。
定时器0:频率计数;定时器1:函数刷新;定时器2:PWM输出。
1、首先是NE555频率测量:
其中TMOD|=0x04为切换定时器为计数模式。
2、其次是PCA实现超声波测量:
(别忘了TX、RX引脚定义)
最后得到的值+3(实际测量在+2.5左右),原因是因为硬件或者程序延时时间等问题有小误差,很多博主和教程里这个地方都有加3,可以自己拿尺子测量一下距离看看是不是这样。
3、PWM输出
首先看题目:
首先找到这个电机驱动引脚连接的位置:(不是去找J3哦)
可以发现它和我们常用的继电器、蜂鸣器在一个地方,这样我们就可以像控制它俩一样控制电机。
输出频率为1khz,那么我们输出信号周期就为1000微秒,分成5份,每份就是200微秒,就可以设置200微秒定时器中断。
这里每份是200微秒,那么之前我们设置的超声波程序整个过程是24微秒*8=192微秒<200微秒,这样才不会因为关闭中断时间过长造成PWM输出异常。
4、PCF8591
这里我设置采集时关闭中断,完成后才打开,以免影响iic时序。如果不关闭的话,实际采集值会来回跳变(大家可以试一试是不是这样),有的教程和博主教学里面没关,可能是我其它程序设置问题。
注意:设置的外设等刷新时间,应该是满足条件的最大值,以免多次采集造成不良影响。
自从第十届开始,采取机器阅卷后,就对采集时间等等性能有姚桥,但本届题目并没有和省赛一样设置外设时间刷新要求,原因可能是超声波、频率等等容易冲突的地方太多了,就放宽了条件,所以我们在设置刷新时间,就适当的加长一点。
完整题目:
完整程序:
MAIN.c
#include <Main.h>
#include <IIC.h>
#include "sonic.h"
void Task_Clock(void)
{
Set_HC573(4,LED);
Set_HC573(5,Actuator_Bit);
if(LED_flag==1){if(++LED_tt == 100)
{
LED_tt = 0;
if(LED_Run==1){LED_ON(State3);LED_Run=0;}
else if(LED_Run==0){LED_OFF(State3);LED_Run=1;}}
}
if(++SEG_tt == 50) { SEG_tt = 0; SEG_Ref = 1; }
if(++KEY_tt == 10) { KEY_tt = 0; KeyScan(); }
if(++AD_tt == 300) { AD_tt = 0; AD_Ref = 1; }
if(++LCM_tt == 500) {LCM_tt = 0; LCM_Ref = 1; }
if(++Freq_tt == 1000) {Freq_tt = 0; Freq_Ref = 1; }
}
void main(void)
{
ALL_Init();
if(AT24C02_read(0X64)!=0x80)
{
AT24C02_write(0x64,0x80);Delay_MS(5);
AT24C02_write(0x00,0);Delay_MS(5);
}
else {Cishu = AT24C02_read(0X00); Delay_MS(5);}
LED_ON(1);
AD_read(0X43);
AD_Value = AD_read(0X43);
AD_Value = AD_Value * 1.96;
Timer0Init();
Timer1Init();
Timer2Init();IE2 |= 0X04;
EA = 1; ET1 = 1;
while(1)
{
if(SEG_Ref == 1)
{
SEG_Ref = 0;
SEG_Refresh();
}
if(KEY_Flag == 1)
{
KEY_Flag = 0;
Task_Key();
}
if(AD_Ref == 1)
{
AD_Ref = 0;
AD_Value = AD_read(0X43); //滑动变阻器0X03,光敏电阻0X01
AD_Value = AD_Value * 1.96;
Shidu=0.2*AD_Value;
if(Shidu<=Shidu_para){AD_write(51);LED_OFF(5);}
else if(Shidu>=80){AD_write(255);LED_ON(5);}
else {AD_write((Shidu-80)*4*51/(80-Shidu_para)+5*51);LED_ON(5);}
}
if(LCM_Ref == 1)
{
LCM_Ref = 0;
LCM=Sonic_Measure()+3;
if((LCM>LCM_para*10)&&(LCM_last<=LCM_para*10))
{
Actuator_Bit|=0x10;Cishu=Cishu+1;AT24C02_write(0x00,Cishu);LED_ON(6);
}
else if((LCM>LCM_para*10)&&(LCM_last>LCM_para*10))
{
LED_ON(6);
}
else if(LCM<=LCM_para*10){Actuator_Bit&=~0x10;LED_OFF(6);}
LCM_last=LCM;
}
if(Freq_Ref == 1)
{
Freq_Ref = 0 ;
Freq_Callback_1s();
if(Freq>Freq_para*100)
{
LED_ON(4);
PWM_Deuty_count=4;
}
else
{
LED_OFF(4);
PWM_Deuty_count=1;
}
}
}
}
void Task_Key(void)
{
if(KEY_Value==4)
{
KEY_Value=0;
if(SEG_Show==1){SEG_Show=2;LED_OFF(1);LED_ON(2);}
else if(SEG_Show==2){SEG_Show=3;LED_OFF(2);LED_ON(3);}
else if(SEG_Show==3){SEG_Show=4;LED_OFF(3);State3=1;LED_flag=1;}
else if(SEG_Show==4){SEG_Show=1;LED_flag=0;LED_OFF(State3);LED_ON(1);}
}
if(KEY_Value==5)
{
KEY_Value=0;
if(SEG_Show==4)
{
if(State3==1){State3=2;LED_OFF(1);}
else if(State3==2){State3=3;LED_OFF(2);}
else if(State3==3){State3=1;LED_OFF(3);}
}
}
if(KEY_Value==6){
KEY_Value=0;
if(SEG_Show==4)
{
if(State3==1)
{
Freq_para=Freq_para+5;
if(Freq_para>120)Freq_para=10;
}
else if(State3==2)
{
Shidu_para=Shidu_para+10;
if(Shidu_para>60)Shidu_para=10;
}
else if(State3==3)
{
LCM_para=LCM_para+1;
if(LCM_para>12)LCM_para=1;
}
}
if(SEG_Show==3)
{
if(State2==1)State2=2;
else State2=1;
}
}
if((KEY_Value==7)&&(KEY_Press_TIME<1000))
{
KEY_Value=0;
if(SEG_Show==4)
{
if(State3==1)
{
Freq_para=Freq_para-5;
if(Freq_para<10)Freq_para=120;
}
else if(State3==2)
{
Shidu_para=Shidu_para-10;
if(Shidu_para<10)Shidu_para=60;
}
else if(State3==3)
{
LCM_para=LCM_para-1;
if(LCM_para<1)LCM_para=12;
}
}
if(SEG_Show==1)
{
if(State1==1)State1=2;
else State1=1;
}
}
if((KEY_Value==7)&&(KEY_Press_TIME>=1000))
{
KEY_Value=0;
Cishu=0;
AT24C02_write(0x00,0);
}
}
void SEG_Refresh(void)
{
if(SEG_Show == 1)
{
DigBuf[0] = 22; DigBuf[1] = 21; DigBuf[2] = 21;
if(State1==1)
{
if(Freq>=10000)
{
DigBuf[3]=Freq/10000;
DigBuf[4]=Freq%10000/1000;
DigBuf[5]=Freq%1000/100;
DigBuf[6]=Freq%100/10;
DigBuf[7]=Freq%10;
}
else if((Freq>=1000)&&(Freq<10000))
{
DigBuf[3]=21;
DigBuf[4]=Freq%10000/1000;
DigBuf[5]=Freq%1000/100;
DigBuf[6]=Freq%100/10;
DigBuf[7]=Freq%10;
}
else if((Freq>=100)&&(Freq<1000))
{
DigBuf[3]=21;
DigBuf[4]=21;
DigBuf[5]=Freq%1000/100;
DigBuf[6]=Freq%100/10;
DigBuf[7]=Freq%10;
}
else if((Freq>=10)&&(Freq<100))
{
DigBuf[3]=21;
DigBuf[4]=21;
DigBuf[5]=21;
DigBuf[6]=Freq%100/10;
DigBuf[7]=Freq%10;
}
}
else if(State1==2)
{
DigBuf[3]=21;
DigBuf[4]=21;
if(Freq>=10000)
{
DigBuf[5]=Freq/10000;
DigBuf[6]=Freq/1000%10+10;
DigBuf[7]=Freq/100%10;
}
else if((Freq>=1000)&&(Freq<10000))
{
DigBuf[5]=21;
DigBuf[6]=Freq/1000%10+10;
DigBuf[7]=Freq/100%10;
}
else if((Freq>=100)&&(Freq<1000))
{
DigBuf[5]=21;
DigBuf[6]=10;
DigBuf[7]=Freq/100%10;
}
}
}
else if(SEG_Show == 2)
{
DigBuf[0] = 23; DigBuf[1] = 21;
DigBuf[2] = 21; DigBuf[3] = 21; DigBuf[4] = 21;
DigBuf[5] = 21; DigBuf[6] = Shidu/ 10; DigBuf[7] = Shidu % 10;
}
else if(SEG_Show == 3)
{
DigBuf[0] = 24; DigBuf[1] = 21; DigBuf[2] = 21;
DigBuf[3] = 21; DigBuf[4] = 21;
if(State2==1)
{
if(LCM>=100)
{
DigBuf[5] = LCM/100;
DigBuf[6] = LCM%100/10;
DigBuf[7] = LCM%10;
}
else if((LCM>=10)&&(LCM<100))
{
DigBuf[5] = 21;
DigBuf[6] = LCM%100/10;
DigBuf[7] = LCM%10;
}
else if((LCM>=0)&&(LCM<10))
{
DigBuf[5] = 21;
DigBuf[6] = 21;
DigBuf[7] = LCM%10;
}
}
else if(State2==2)
{
if(LCM>=100)
{
DigBuf[5] = LCM/100+10;
DigBuf[6] = LCM%100/10;
DigBuf[7] = LCM%10;
}
else if((LCM>=10)&&(LCM<100))
{
DigBuf[5] = 10;
DigBuf[6] = LCM%100/10;
DigBuf[7] = LCM%10;
}
else if((LCM>=0)&&(LCM<10))
{
DigBuf[5] = 10;
DigBuf[6] = 0;
DigBuf[7] = LCM%10;
}
}
}
else if(SEG_Show == 4)
{
DigBuf[0]=25;DigBuf[1]=State3;
DigBuf[2]=21;
DigBuf[3]=21;
DigBuf[4]=21;
if(State3==1)
{
if(Freq_para>=100)
{
DigBuf[5]=Freq_para%1000/100;
DigBuf[6]=Freq_para%100/10+10;
DigBuf[7]=Freq_para%10;
}
else
{
DigBuf[5]=21;
DigBuf[6]=Freq_para%100/10+10;
DigBuf[7]=Freq_para%10;
}
}
else if(State3==2)
{
DigBuf[5]=21;
DigBuf[6]=Shidu_para%100/10;
DigBuf[7]=Shidu_para%10;
}
else if(State3==3)
{
DigBuf[5]=21;
DigBuf[6]=LCM_para%100/10+10;
DigBuf[7]=LCM_para%10;
}
}
}
void Delay12us() //@12.000MHz
{
unsigned char i;
_nop_();
_nop_();
i = 33;
while (--i);
}
// 使用PCA模块计时,Sysclk不分频做时钟输入
void Sonic_Init()
{
CMOD = 0x88;
CCON = 0;
CH = 0;
CL = 0;
}
void Sonic_SendTrig()
{
unsigned char i;
// 关中断发驱动波形
EA = 0;
for (i = 0; i < 8; i++) {
TX = 1;
Delay12us();
TX = 0;
Delay12us();
}
EA = 1;
}
unsigned int Sonic_Measure()
{
unsigned char cf = 0;
Sonic_Init();
Sonic_SendTrig();
// 开始计时
CR = 1;
while (RX) {
// 计数器溢出处理
if (CF == 1) {
cf++;
CF = 0;
}
if (cf == 10) {
CR = 0;
return 65535;
}
}
CR = 0;
// (((CH * 256 + CL) * 0.017) / 12:本轮计数的距离
// 92.8427 * cf:溢出计数距离
return (unsigned int ) (((CH * 256 + CL) * 0.017) / 12 + 92.8427 * cf);
}
void KeyScan(void)
{
switch(KeyState)
{
case KEY_Check: if((P30 == 0) || (P31 == 0) || (P32 == 0) || (P33 == 0)) KeyState = KEY_Press;break;
case KEY_Press:
{
if(P30 == 0) KEY_Value = 7;
else if(P31 == 0) KEY_Value = 6;
else if(P32 == 0) KEY_Value = 5;
else if(P33 == 0) KEY_Value = 4;
KeyState = KEY_Release;
KEY_Press_TIME = 10;
}
break;
case KEY_Release:
{
if((P30 == 0) || (P31 == 0) || (P32 == 0) || (P33 == 0))
{
KEY_Press_TIME = KEY_Press_TIME + 10;
}
else
{
KeyState = KEY_Check;
KEY_Flag = 1;
}
}
break;
default: break;
}
}
void Timer2(void) interrupt 12
{
EA=0;
if(PWM_count==0)Actuator_Bit|= 0x20;
else if(PWM_count == PWM_Deuty_count ) { Actuator_Bit&=~0x20; }
else if(PWM_count == 5 ) { PWM_count = 0; Actuator_Bit|= 0x20; }
Set_HC573(5,Actuator_Bit);
EA=1;
PWM_count++;
}
void Timer2Init(void) //200微秒@12.000MHz
{
AUXR |= 0x04; //定时器时钟1T模式
T2L = 0xA0; //设置定时初始值
T2H = 0xF6; //设置定时初始值
AUXR |= 0x10; //定时器2开始计时
}
void Timer1(void) interrupt 3
{
Set_HC573(6,0x00);
Set_HC573(7,tab[DigBuf[DigCom]]);
Set_HC573(6,0x01<<DigCom);
if(++DigCom==8)DigCom=0;
Task_Clock();
}
void Timer1Init(void) //1毫秒@12.000MHz
{
AUXR |= 0x40; //定时器时钟1T模式
TMOD &= 0x0F; //设置定时器模式
TL1 = 0x20; //设置定时初始值
TH1 = 0xD1; //设置定时初始值
TF1 = 0; //清除TF1标志
TR1 = 1; //定时器1开始计时
}
void Timer0Init(void) //@12.000MHz
{
AUXR |= 0x80; //定时器时钟1T模式
TMOD |= 0x04; //设置定时器模式
TL0 = 0x00; //设置定时初始值
TH0 = 0x00; //设置定时初始值
TF0 = 0; //清除TF0标志
}
void Freq_Callback_1s()
{
TR0 = 0;
Freq = TH0 * 256 + TL0;
TL0 = 0x0;
TH0 = 0x0;
TF0 = 0;
TR0 = 1;
}
void All_Init()
{
Set_HC573(5,0x00);
Set_HC573(4,0xff);
Set_HC573(6,0x00);
}
void Set_HC573(unsigned char channel,unsigned char dat)
{
P0=dat;
switch(channel)
{
case 4:
P2=0x80;
break;
case 5:
P2=0xa0;
break;
case 6:
P2=0xc0;
break;
case 7:
P2=0xe0;
break;
}
P2=0;
}
void Delay_MS(unsigned int MS) //@12.000MHz
{
unsigned int k;
unsigned char i, j;
for(k=0;k<MS;k++)
{
i = 12;
j = 169;
do
{
while (--j);
} while (--i);
}
}
MAIN.h程序
#ifndef __MAIN_H__
#define __MAIN_H__
#include <STC15F2K60S2.H>
#include <intrins.h>
sbit TX = P1^0 ;
sbit RX = P1^1 ;
unsigned char LED=0xff;
unsigned char Actuator_Bit = 0X00;
unsigned char code tab[]={0XC0,0XF9,0XA4,0XB0,0X99,0X92,0X82,0XF8,0X80,0X90,\
0X40,0X79,0X24,0X30,0X19,0X12,0X02,0X78,0X00,0X10,\
0XBF,0XFF,0x8e,0x89,0x88,0x8c};
#define LED_ON(n) {LED&=~(0x01<<(n-1)); }
#define LED_OFF(n) {LED|=(0x01<<(n-1));}
unsigned char DigCom = 0 ;
unsigned char DigBuf[8] = {21,21,21,21,21,21,21,21};
typedef enum
{
KEY_Check, //检测状态
KEY_Press, //按下状态
KEY_Release, //等待松开状态
Key_Over //按下之后松开,按键结束状态
}KEY_State;
KEY_State KeyState = KEY_Check; //初始设置按键初始化状态为检测状态
unsigned char KEY_Value = 0;
unsigned char KEY_tt = 0; //按键扫描时间计时
unsigned int KEY_Press_TIME = 10; //按键按下时长
bit KEY_Flag = 0; //按键按下又松开之后标识位
unsigned int LED_tt = 0 ;
bit LED_Ref =0;
unsigned int SEG_tt =0;
bit SEG_Ref = 0 ;
unsigned int AD_Value = 0;
unsigned int AD_tt = 0;
bit AD_Ref = 0;
unsigned int LCM_tt = 0 ;
bit LCM_Ref = 0 ;
unsigned int LCM = 0 ;
unsigned int LCM_last=0;
unsigned int xdata PWM_count = 0;
unsigned char xdata PWM_Deuty_count = 0;
unsigned int Freq = 0;
unsigned int Freq_tt = 0;
bit Freq_Ref = 0;
unsigned char SEG_Show = 1 ;
unsigned int Cishu=0;
unsigned char State1=1;
unsigned char State2=1;
unsigned char State3=1;
unsigned char Shidu=0;
unsigned char Freq_para=90;
unsigned char Shidu_para=40;
unsigned char LCM_para=6;
bit LED_flag=0;
bit LED_Run=0;
void Delay_MS(unsigned int MS);
void Set_HC573(unsigned char channel,unsigned char dat);
void ALL_Init(void);
void Timer0Init(void); //1毫秒@12.000MHz
void KeyScan(void);
void Task_Clock(void);
void SEG_Refresh(void);
void Task_Key(void);
void Delay12us(); //@12.000MHz
void Timer1Init(void); //10微秒@12.000MHz
void Sonic_Init() ;
void Sonic_SendTrig() ;
void Freq_Callback_1s() ;
void Timer2Init();
#endif
IIC.c程序文章来源:https://www.toymoban.com/news/detail-474501.html
#include <STC15F2K60S2.H>
#include "intrins.h"
//总线引脚定义
sbit sda = P2^1; /* 数据线 */
sbit scl = P2^0; /* 时钟线 */
#define DELAY_TIME 5
//
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);
}
unsigned char AT24C02_read(unsigned char add)
{
unsigned char da;
I2CStart();
I2CSendByte(0XA0);
I2CWaitAck();
I2CSendByte(add);
I2CWaitAck();
I2CStop();
I2CStart();
I2CSendByte(0XA1);
I2CWaitAck();
da = I2CReceiveByte();
I2CSendAck(1);
I2CStop();
return da;
}
void AT24C02_write(unsigned char add,unsigned char dat)
{
I2CStart();
I2CSendByte(0xA0);
I2CWaitAck();
I2CSendByte(add);
I2CWaitAck();
I2CSendByte(dat);
I2CWaitAck();
I2CStop();
}
unsigned char AD_read(unsigned char add)
{
unsigned char temp;
EA=0;
I2CStart();
I2CSendByte(0X90);
I2CWaitAck();
I2CSendByte(add);
I2CWaitAck();
I2CStop();
I2CStart();
I2CSendByte(0X91);
I2CWaitAck();
temp=I2CReceiveByte();
I2CSendAck(1);
I2CStop();
EA=1;
return temp;
}
void AD_write(unsigned char dat)
{
EA=0;
I2CStart();
I2CSendByte(0X90);
I2CWaitAck();
I2CSendByte(0X40);
I2CWaitAck();
I2CSendByte(dat);
I2CWaitAck();
I2CStop();
EA=1;
}
IIC.h程序文章来源地址https://www.toymoban.com/news/detail-474501.html
#ifndef _IIC_H
#define _IIC_H
static void I2C_Delay(unsigned char n);
void I2CStart(void);
void I2CStop(void);
void I2CSendByte(unsigned char byt);
unsigned char I2CReceiveByte(void);
unsigned char I2CWaitAck(void);
void I2CSendAck(unsigned char ackbit);
unsigned char AT24C02_read(unsigned char add);
void AT24C02_write(unsigned char add,unsigned char dat);
unsigned char AD_read(unsigned char add);
void AD_write(unsigned char dat);
#endif
到了这里,关于蓝桥杯第十三届单片机国赛程序的文章就介绍完了。如果您还想了解更多内容,请在右上角搜索TOY模板网以前的文章或继续浏览下面的相关文章,希望大家以后多多支持TOY模板网!