蓝桥杯单片机第10届国赛

 遇到的问题:

  1. 矩阵键盘中的P34口和测频率的P34会冲突导致键盘不能正常使用。所以键盘使用到P34的时候注意是否已经拔掉了。
  2. 使用超声波测距时要用不自动重装的,如果初始化成了自动重装模式会测不准。
  3. DAC输出不能在中断里一直执行,否则测不了距离。应该放在while(1)
  4. UART串口接收数据的处理要放在主函数里,不能放在1ms中断。
  5. 串口通信\r\n的作用。
  6. 长按短按功能。

a7fa73a53f5e483bb203aa4f10caa3b1.png

f10bbe732bb0459e9a93b9895eaa8f4c.png

f6ce0067d62f4e65983deef0395f0eab.png

3b6b7daa1ea942eba9e8eef12eaf409a.png

cccb18a344284f26979bad2634857e3a.png

e7fe9e860d0144818dc87ee40e2fb757.png

 

main.c

#include <STC15F2K60S2.H>
#include <intrins.h>
#include "iic.h"
#include "onewire.h"

code unsigned char Seg_Table[] = {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};
unsigned char smg[8];
unsigned char pre1=30,pre2=35; //先前参数 用来对比是否改变了参数
unsigned char change_times=0; //参数变动次数
unsigned char pram_temp=30;//温度参数
unsigned char pram_dist=35;//距离参数

bit dac_state=1;
bit busy; //串口

unsigned char rx_buf[10];
unsigned char rx_cnt=0;
unsigned char te[2]={'S','T'};

typedef struct
{
	unsigned char b1:1;
	unsigned char b2:1;
	unsigned char b3:1;
	unsigned char b4:1;
	unsigned char b5:1;
	unsigned char b6:1;
	unsigned char b7:1;
	unsigned char b8:1;
}Bits;

typedef union
{
	unsigned char Hex;
	Bits B;
}HexToB;

HexToB led_ctrl;

void vDevice_Process(unsigned char p2dat,unsigned char p0dat)
{
	P0 = p0dat;
	P2 = (P2&0x1f)|p2dat;
	P2 = P2&0x1f;
}
//-------定时器-----------
void Timer2Init(void)		//1毫秒@12.000MHz
{
	AUXR |= 0x04;		//定时器时钟1T模式
	T2L = 0x20;		//设置定时初值
	T2H = 0xD1;		//设置定时初值
	AUXR |= 0x10;		//定时器2开始计时
	
	IE2 |= 0x04;
	EA = 1;
}

void UartInit(void)		//4800bps@12.000MHz
{
	SCON = 0x50;		//8位数据,可变波特率
	AUXR |= 0x40;		//定时器1时钟为Fosc,即1T
	AUXR &= 0xFE;		//串口1选择定时器1为波特率发生器
	TMOD &= 0x0F;		//设定定时器1为16位自动重装方式
	TL1 = 0x8F;		//设定定时初值
	TH1 = 0xFD;		//设定定时初值
	ET1 = 0;		//禁止定时器1中断
	TR1 = 1;		//启动定时器1
	EA=1;
	ES=1;
}

//-------温度传感器----------
unsigned int tempture;
unsigned char cnt_temp;
void vRead_temp()
{
	if(cnt_temp>100)
	{
		cnt_temp=0;
		tempture = vRead_18b20()*100;
	}
}

//-------超声波测距--------
void vSend_wave()
{
	unsigned char i,j;
	for(i=0;i<8;i++)
	{
		P10 = 1;
		for(j=0;j<25;j++)
		_nop_();
		P10 = 0;
		for(j=0;j<25;j++)
		_nop_();
	}
}

unsigned char vRecive_wave()
{
	unsigned char temp;
	TL0=0;TH0=0;
	vSend_wave();
	TR0=1;
	while((P11==1)&&(TF0==0));
	TR0=0;
	if(TF0==1)
	{
		TF0=0;
		temp=99;
	}
	else
	{
		temp = ((TH0<<8)|TL0)*0.017;
		if(temp>99)temp=99;		
	}	
	return temp;
}

unsigned char dist; //0-99
unsigned char cnt_dist;
void vGet_distance()
{
	if(cnt_dist>=100)
	{
		cnt_dist=0;
		dist = vRecive_wave();
	}
}

//--------DAC输出-------------
unsigned char cnt_dac;
void vDAC_out()
{
	if(cnt_dac>=10)
	{
		cnt_dac=0;
		if(dac_state==1)//启动状态
		{
			if(dist>=pram_dist) vOut_V(102);
			if(dist<pram_dist) vOut_V(204);
		}
		else //停止状态 固定0.4V
		{
			vOut_V(20);
		}
	}
	
}

//-------数码管-----------
//数码管操作
unsigned char mode1=0;
unsigned char mode2=1;
void vSmg_Process()
{
	if(mode1==0)
	{
		if(mode2==0)
		{
			smg[0]=0xc6;
			smg[1]=0xff;
			smg[2]=0xff;
			smg[3]=0xff;
			smg[4]=Seg_Table[tempture/1000];
			smg[5]=Seg_Table[tempture/100%10]&0x7f;
			smg[6]=Seg_Table[tempture/10%10];
			smg[7]=Seg_Table[tempture%10];
		}
		else if(mode2==1)
		{
			smg[0]=0xc7;
			smg[1]=0xff;
			smg[2]=0xff;
			smg[3]=0xff;
			smg[4]=0xff;
			smg[5]=0xff;
			smg[6]=Seg_Table[dist/10];
			smg[7]=Seg_Table[dist%10];
		}
		else if(mode2==2)
		{
			smg[0]=0xc8;
			smg[1]=0xff;
			smg[2]=0xff;
			smg[3]=0xff;
			smg[4]=0xff;
			smg[5]=0xff;
			smg[6]=Seg_Table[change_times/10];
			smg[7]=Seg_Table[change_times%10];
		}
	}
	else if(mode1==1)
	{
		if(mode2==0)
		{
			smg[0]=0x8c;
			smg[1]=0xff;
			smg[2]=0xff;
			smg[3]=Seg_Table[1];
			smg[4]=0xff;
			smg[5]=0xff;
			smg[6]=Seg_Table[pre1/10];
			smg[7]=Seg_Table[pre1%10];
		}
		else if(mode2==1)
		{
			smg[0]=0x8c;
			smg[1]=0xff;
			smg[2]=0xff;
			smg[3]=Seg_Table[2];
			smg[4]=0xff;
			smg[5]=0xff;
			smg[6]=Seg_Table[pre2/10];
			smg[7]=Seg_Table[pre2%10];
		}
	}
	
}

//数码管显示
void vSmg_Show()
{
	static unsigned char i;
	vDevice_Process(0xc0,0x00);
	vDevice_Process(0xe0,smg[i]);
	vDevice_Process(0xc0,0x01<<i);
	i = (i+1)%8;
}

//-------矩阵键盘------------
unsigned char vScan_Keys()
{
	unsigned char key_io=0xff;
	P32=0;P33=0;
	P34=1;P35=1;
	if(P35==0) key_io=0xd0;
	if(P34==0) key_io=0xe0;
	
	P32=1;P33=1;
	P34=0;P35=0;
	if(P32==0) key_io=key_io|0x0b;
	if(P33==0) key_io=key_io|0x07;
	
	return key_io;
}

unsigned char Trg,Cont;
void vThree_line()
{
	unsigned char key_io,ReadData;
	key_io = vScan_Keys();
	ReadData = key_io^0xff;
	
	Trg = ReadData&(ReadData^Cont);
	Cont = ReadData;
}

unsigned char cnt_key;
unsigned int cnt_k12;//长按1s计时
unsigned int cnt_k13;
void vKeys_Process()
{
	if(cnt_key>=10)
	{
		cnt_key=0;
		vThree_line();	

		if(Trg==0x18)  //S16
		{
			if(mode1==1&&mode2==0) 
			{
				pre1=pre1-2;
			}
			if(mode1==1&&mode2==1) 
			{
				pre2=pre2-5;
			}			
		}
		
		if(Trg==0x14)  //S17
		{
			if(mode1==1&&mode2==0) 
			{
				pre1=pre1+2;
			}
			if(mode1==1&&mode2==1) 
			{
				pre2=pre2+5;
			}
			
		}
		
		//长按
		if(Cont==0x28)//S12
		{
			cnt_k12++;//10ms加一次  100次就是1秒		
		}
		if(Cont==0x24)
		{
			cnt_k13++;
		}		
		
		if(Cont==0x00&&Trg==0x00)
		{
			if(cnt_k12>=100)
			{
				change_times=0;
				vWrite_eeprom(0x20,change_times);
			}
			else if(cnt_k12!=0) //小于100且不等于0是短按
			{
				if(mode1==0)mode2 = (mode2+1)%3;
				if(mode1==1)mode2 = (mode2+1)%2;
			}
			if(cnt_k13>=100)
			{
				dac_state=!dac_state;
			}
			else if(cnt_k13!=0)
			{
				mode1 = (mode1+1)%2;
				if(mode1==0)//切回了数据界面,检查参数是否发生改变
				{
					if(pre1!=pram_temp)  //如果参数发生了改变
					{
						pram_temp=pre1;
					  change_times++;
						vWrite_eeprom(0x20,change_times);
					}
					else if(pre2!=pram_dist)
					{
						pram_dist=pre2;
					  change_times++;				
						vWrite_eeprom(0x20,change_times);			
					}
				}
				if(mode1==1) //切到参数界面时先把暂时pre改为真实参数pram
				{
					pre1 = pram_temp;
					pre2 = pram_dist;
				}
				mode2=0;
			}
			cnt_k13=0;
			cnt_k12=0;
		}	
	}
}

//---------LED指示灯--------
void vLED_Process()
{
	if(tempture>pram_temp*100)
	{
		led_ctrl.B.b1=0;
	}
	else 
	{
		led_ctrl.B.b1=1;
	}
	
	if(dist>pram_dist)
	{
		led_ctrl.B.b2=0;
	}
	else 
	{
		led_ctrl.B.b2=1;
	}
	
	if(dac_state==1)
	{
		led_ctrl.B.b3=0;
	}
	else 
	{
		led_ctrl.B.b3=1;
	}
	vDevice_Process(0x80,led_ctrl.Hex);
}






/*----------------------------
发送串口数据
----------------------------*/
void SendData(unsigned char dat)
{
    while (busy);               //等待前面的数据发送完成
    busy = 1;
    SBUF = dat;                 //写数据到UART数据寄存器
}

/*----------------------------
发送字符串
----------------------------*/
void SendString(char *s)
{
    while (*s)                  //检测字符串结束标志
    {
        SendData(*s++);         //发送当前字符
    }
}

//串口数据处理
bit flag_uart;
void vUart_Porcess()
{
	if(flag_uart==1)
	{
		flag_uart=0;
	  if(rx_buf[0]=='S'&&rx_buf[1]=='T')
		{
			SendData('$');
			SendData(dist/10+'0');SendData(dist%10+'0');SendData(',');
			SendData(tempture/1000+'0');SendData(tempture/100%10+'0');SendData('.');SendData(tempture/10%10+'0');SendData(tempture%10+'0');
			SendString("\r\n");
		}
		
		else if(rx_buf[0]=='P'&&rx_buf[1]=='A'&&rx_buf[2]=='R'&&rx_buf[3]=='A')
		{
			SendData('#');
			SendData(pram_dist/10+'0');SendData(pram_dist%10+'0');SendData(',');
			SendData(pram_temp/10+'0');SendData(pram_temp%10+'0');SendString("\r\n");
		}
		else
		{
			SendString("ERROR\r\n");
		}
	}
}


//系统初始化
void vSystem_init()
{
	led_ctrl.Hex=0xff;
	vDevice_Process(0x80,0xff);
	vDevice_Process(0xa0,0x00);
}

void main()
{
	vSystem_init();
	Timer2Init();
	UartInit();
	while(1)
	{
		vSmg_Process();
		vRead_temp();
		vGet_distance();
		vKeys_Process();
		vUart_Porcess();
		vDAC_out();
	}
}

void Timer2_service() interrupt 12
{
	vSmg_Show();
	vLED_Process();
	cnt_temp++;cnt_dist++;cnt_key++;cnt_dac++;
}


/*----------------------------
UART 中断服务程序
-----------------------------*/
void Uart() interrupt 4
{
    if (RI)
    {
      RI = 0;                 //清除RI位
		  rx_buf[rx_cnt++]=SBUF;
			if(rx_buf[rx_cnt-1]=='\n')
			{
				flag_uart=1;
				rx_cnt=0;
			}
    }
    if (TI)
    {
        TI = 0;                 //清除TI位
        busy = 0;               //清忙标志
    }
}

IIC.c

/*	#   I2C代码片段说明
	1. 	本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
	2. 	参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
		中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include <reg52.h>
#include <intrins.h>

#define DELAY_TIME	5

sbit sda=P2^1;
sbit scl=P2^0;


void Delay5ms()		//@12.000MHz
{
	unsigned char i, j;

	i = 59;
	j = 90;
	do
	{
		while (--j);
	} while (--i);
}


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);
}

//EEPROM 存储
void vWrite_eeprom(unsigned char addr,unsigned char dat)
{
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(addr);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
	Delay5ms();
}
//EEPROM 读取
unsigned char vRead_eeprom(unsigned char addr)
{
	unsigned char dat;
	I2CStart();
	I2CSendByte(0xa0);
	I2CWaitAck();
	I2CSendByte(addr);
	I2CWaitAck();
	
	I2CStart();
	I2CSendByte(0xa1);
	I2CWaitAck();
	dat = I2CReceiveByte();
	I2CSendAck(1);
	I2CStop();
	return dat;
}

//DAC 模拟电压输出
void vOut_V(unsigned char dat)
{
	I2CStart();
	I2CSendByte(0x90);
	I2CWaitAck();
	I2CSendByte(0x40);
	I2CWaitAck();
	I2CSendByte(dat);
	I2CWaitAck();
	I2CStop();
}


onewire.c

/*	# 	单总线代码片段说明
	1. 	本文件夹中提供的驱动代码供参赛选手完成程序设计参考。
	2. 	参赛选手可以自行编写相关代码或以该代码为基础,根据所选单片机类型、运行速度和试题
		中对单片机时钟频率的要求,进行代码调试和修改。
*/
#include <reg52.h>
#include <intrins.h>

sbit DQ=P1^4;

void Delay_OneWire(unsigned int t)  
{
	unsigned char i;
	while(t--){
		for(i=0;i<12;i++);
	}
}

//
void Write_DS18B20(unsigned char dat)
{
	unsigned char i;
	for(i=0;i<8;i++)
	{
		DQ = 0;
		DQ = dat&0x01;
		Delay_OneWire(5);
		DQ = 1;
		dat >>= 1;
	}
	Delay_OneWire(5);
}

//
unsigned char Read_DS18B20(void)
{
	unsigned char i;
	unsigned char dat;
  
	for(i=0;i<8;i++)
	{
		DQ = 0;
		dat >>= 1;
		DQ = 1;
		if(DQ)
		{
			dat |= 0x80;
		}	    
		Delay_OneWire(5);
	}
	return dat;
}

//
bit init_ds18b20(void)
{
  	bit initflag = 0;
  	
  	DQ = 1;
  	Delay_OneWire(12);
  	DQ = 0;
  	Delay_OneWire(80);
  	DQ = 1;
  	Delay_OneWire(10); 
    initflag = DQ;     
  	Delay_OneWire(5);
  
  	return initflag;
}

//温度读取
float vRead_18b20()
{
	unsigned char LSB,MSB;
	float temp;
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0x44);
	
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0xbe);
	
	LSB = Read_DS18B20();
	MSB = Read_DS18B20();
	
	temp =((MSB<<8)|LSB)*0.0625;
	
	return temp;
}

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值