【蓝桥杯单片机国赛 第十届】

做题思路

首先写上要做的模块,界面,晓得细节
一页纸就能让你不用看pdf即可写出整套题这种
简单示范:

首先smg

void smg()
{
	P2 = (P2&0x1f)|0xc0; P0 = T_COM[smg_i]; P2 = (P2&0x1f);
	P2 = (P2&0x1f)|0xe0; P0 = ~table[smg_i]; P2 = (P2&0x1f);
	smg_i++;
	smg_i &= 0x07;
}

长短矩阵按键

我的思路:

  • 首先先把状态机一次按键写出(用于去抖动)
  • 在一次按键的基础上,检测按键按下(无抖动的一次按键下) 到松开,所花的时间是否大于950ms
  • 最后赋值(是否*10)来区别长短按键
bit flag_changan; //此标志位表示按键是否按下状态,
//以此为标志来计时,当按键松开时,在进行判断长短按键后,记得将计数值清零
void tm1_isr() interrupt 3 using 1
{
    if (count-- == 0)               //1ms * 1000 -> 1s
    {
        count = 1000;               //reset counter
    }

		if(flag_changan) {key_count++;} else key_count = 0;
}
u8 key_scan()
{
	u8 key_return = 99, key = 99;
	h1 = 1; h2 = 1; h3 = 1; h4 = 1;
	l1 = 1; l2 = 1; l3 = 0; l4 = 1;
	if(h3 != 1) key = 13;
	if(h4 != 1) key = 12;
	h1 = 1; h2 = 1; h3 = 1; h4 = 1;
	l1 = 1; l2 = 1; l3 = 1; l4 = 1;
	if(h3 != 1) key = 17;
	if(h4 != 1) key = 16;
	switch(key_state)
	{
		case 0: if(key != 99) key_state = 1; flag_changan = 0; break;
		case 1: if(key == 99) key_state = 0; 
		        else{key_val = key; key_state = 2; flag_changan = 1; } break; //以此判断是否有抖动,若无抖动,开始计时,并记录键值
		case 2: if(key == 99) {  if(key_count>980) key_return =  key_val*10;   //changan
                             else  key_return =  key_val;    
                             key_state = 0;  flag_changan = 0; } //状态2主要判断按键是否松开,若松开就可以判断计时长短,否则一直停留此状态。
            break;   //每按一次键就计时
	return 		key_return;											 
	}

串口收发问题

一般我们使用串口1和串口2,而用于串口1的定时器可以是T0,也可以是T2
但要注意,串口1的中断使能为ES = 1;
而串口2的中断使能为IE2 = 1;
然后在使用isp自动生成波特率代码时要注意咯,在本题中由于定时器0超声波计时(12分频),定时器1用于1ms中断,控制所用程序的一个计时,故我们串口就用定时器2记得区分串口中断!(记得勾选上)
在这里插入图片描述
在这里插入图片描述
一个完善的流程就是:
首先isp生成 定时器2串口1 4800bourd的 void UartInit(void) 函数
然后串口重定向

#include "stdio.h"
char putchar (char c)
{
	ES = 0;
	SBUF = c;
	while(TI != 1);
	TI = 0;
	ES = 1;
	return c;
}

就可以自用的运用printf函数进行单片机随上位机的发送信息
但要注意,printf("$%d,%d\r\n",(int)distance_index,(int)temp_index);输出的数值要强制转化为int才能输出正确的数值

最后想要上位机发送信息给单片机,需要加入串口中断函数,将接收到的值用字符串存储起来。

void Uart_Isr() interrupt 4 using 1
{
	u8 a;
    if (RI)
    {
        RI = 0;             //Clear receive interrupt flag
			  a = SBUF;
			  str[recv] = a;
			  recv++;

    }
    if (TI)
    {
        TI = 0;             //Clear transmit interrupt flag

    }
}

这样,一个完整的串口收发就完成了

首先附上标准代码

void Uart_Isr() interrupt 4 using 1
{
	u8 a,i;
    if (RI)
    {
        RI = 0;             //Clear receive interrupt flag
        a = SBUF;          //P0 show UART data
			  receive[rcv] = a;
			  rcv++;
    }
    if (TI)
    {
        TI = 0;             //Clear transmit interrupt flag
        busy = 0;           //Clear transmit busy flag
    }
}

串口重定向:用printf("");来发送字符串
printf("%d",t);可以发送变量
记得加头文件#include<stdio.h>

char putchar(char c)   //串口重定向
{
	ES=0;			//关串口中断
	SBUF=c;			
	while(TI!=1);	//等待发送成功
	TI=0;			//清除发送中断标志
	ES=1;			//开串口中断
	return c;
}

在上位机发送命令小例子
字符 ‘’
字符串 “”
注意下述代码放在while函数里哟,不能放在中断~~~原因在最底部

				 if(rcv>2&&	receive[rcv-2] == '\r' && receive[rcv-1] == '\n') 
				 {
					 rcv = 0;
				for (i = 0;i <8;i++)
					{
						receive[i] = '\0';
					}
				 }
				if(receive[0] == 'S' && receive[1] == 'T') {printf("the Temp is %d ℃\n\t",t);}

第二次写的时候发现\r\n占了4个字节,我也觉得很奇怪,所以在main函数中,检测串口接收的代码就写成了

			if(str[recv-1] =='n')			
			{
			if(str[0] == 'S' && str[1] == 'T' )
				{
					printf("$%d,%f\r\n",(int)distance,(float)temp*0.01);
				}
			else if(str[0] == 'P' && str[1] == 'A'&& str[2] == 'R' && str[3] == 'A' )
				{
					printf("$%d,%d\r\n",(int)distance_index,(int)temp_index);
				}
			else printf("ERROR\r\n");
//			if(str[recv-1] =='n')				
			{
				for(i=0;i<10;i++)
				{
					str[i] = '\0';
				}
				recv = 0;
			}
		}

DS18B20

特别好写,for延时12次。在这里插入图片描述
最后也只用写这么点代码就可以读温度啦
首先定义变量
然后初始化
然后skip rom
然后转换温度
转换温度记得要延时一会(若还是读不出来就要关中断啦)
然后我们要读温度啦,继续初始化
然后skip rom
然后先读低再度高
将所读的加起来16位数据右移4位(*0.0625)就是真实温度,但考虑到小数不方便,直接我们放大100倍得u16
最后记得要返回温度哟

u16 r_t()
{
	u8 l,h;
	u16 temp;
	init_ds18b20();
	Write_DS18B20(0xcc);
	Write_DS18B20(0x44);
	Delay_OneWire(20);

	init_ds18b20();	
	Write_DS18B20(0xcc);
	Write_DS18B20(0xbe);
	l = Read_DS18B20();
	h = Read_DS18B20();
	temp = ((u16)h<<8|l)*6.25;
	return temp;
}

超声波

记得跳线帽要插好,不然就是一直99(害)
超声波的思路就是通过发送8个脉冲 {TX = 1;延时 TX = 0; 延时}(8个)
发送8个是为了超声波能够接受回数据
然后打开定时器0(初始化定时器0时记得清空TL0,TH0 以及 12分频)
while(TF0 != 1 && RX != 0 ); //注意这个为&&,两个同时满足才会一直等待
while语句来记录接收到信号的时间,如果没有接收到就会溢出,我们直接写distance = 99 即可。
同时记得数据初始化,方便下一次的定时计数。

void sendsonic()
{
	u8 i;
	for(i=0;i<8;i++)
	{
		TX = 1;
		somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;
		TX = 0;
		somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;somenop;
	}
}
void r_distance()
{
	sendsonic();
	TR0 = 1; //counter0 start count
	while(TF0 != 1 && RX != 0 ); //注意这个为&&,两个同时满足才会一直等待
	TR0 = 0;
	if(RX == 0) 
	{
		distance = (TH0*256+TL0)*0.017;
		TL0 = 0;
	    TH0 = 0;
	}
	else 
	{distance = 99;	
		TF0 = 0;
		TL0 = 0;
	    TH0 = 0;
	}
}

AT24c02

这个也是照着新派呢手册打代码,记得DAC输出电压通道是0x40
并且读取eeprom的数据要延时5ms,不然会有问题,只需要在前面加就行啦

	 Delay5ms()	;
	 index_change = at24_r(0x55);
	 at24_w(0x55,++index_change);
void at24_w(u8 add,u8 dat)
{
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	IIC_SendByte(add);
	IIC_WaitAck();
	IIC_SendByte(dat);
	IIC_WaitAck();
	IIC_Stop();
}

u8 at24_r(u8 add)
{
	u8 temp;
	IIC_Start();
	IIC_SendByte(0xa0);
	IIC_WaitAck();
	IIC_SendByte(add);
	IIC_WaitAck();

		IIC_Start();
	IIC_SendByte(0xa1);
	IIC_WaitAck();
  temp = IIC_RecByte();
	IIC_Stop();
	return temp;
}

最后串口的问题

在这里插入图片描述
在代码1中,你想在串口中断里发送一堆数据??
串口中断似乎一次智能处理一个字符,而你想用printf发字符串,显然寄了
所以还是安心放在while函数里吧!

  • 13
    点赞
  • 53
    收藏
    觉得还不错? 一键收藏
  • 10
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值