首先写上要做的模块,界面,晓得细节
一页纸就能让你不用看pdf即可写出整套题这种
简单示范:
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;
}
我的思路:
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
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;
}
}
特别好写,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;
}
}
这个也是照着新派呢手册打代码,记得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函数里吧!