
对读的操作

PICC精确延时
延时函数深入了解一下就能设计出一个理想的框价出来。
一般的我们都用
for(x=100;--x;){;}
等价于
x=100;
while(--x){;};
来写一个延时函数。
在这里要特别注意:X=100,并不表示只运行100个指令时间就跳出循环。
可以看看编译后的汇编:
x=100;while(--x){;}
汇编后:
loop
从代码可以看出总的指令是是303个,其公式是8+3*(X-1)。注意其中循环周期是X-1是99个。
这里总结的是x为char类型的循环体,当x为int时候,其中受X值的影响较大。
建议设计一个char类型的循环体,然后再用一个循环体来调用它,可以实现精确的长时间的延时。
下面给出一个能精确控制延时的函数,此函数的汇编代码是最简洁、最能精确控制指令时间的:
void delay(char x,char y){
}
其指令时间为:7+(3*(Y-1)+7)*(X-1)
如果再加上函数调用的call指令、页面设定、传递参数花掉的7个指令。
则是:14+(3*(Y-1)+7)*(X-1)。
如果要求不是特别严格的延时,可以用这个函数:
void delay(){
}
此函数在4M晶体下产生10003us的延时,也就是10MS。
如果把D改成2000,则是20003us,以此类推。
有朋友不明白,为什么不用while(x--) 后减量,来控制设定X值是多少就循环多少周期呢?
现在看看编译它的汇编代码:
loop
可以看出循环体中多了一条指令,不简洁。所以在PICC中最好用 前减量 来控制循环体。
再谈谈这样的语句:
for(x=100;--x;){;}和for(x=0;x<100;x++){;}
从字面上看2者意思一样,但可以通过汇编查看代码。后者代码雍长,而前者就很好的汇编出了简洁的代码。
所以在PICC中最好用前者的形式来写循环体,好的C编译器会自动把增量循环化为减量循环。因为这是由处理器硬件特性决定的。
PICC并不是一个很智能的C编译器,所以还是人脑才是第一的,掌握一些经验对写出高效,简洁的代码是有好处的
endcite
那个延时公式还是很重要的,单位是us
之后就贴上代码
#include
#include
__CONFIG(1,XT) ;
__CONFIG(2,WDTDIS) ;
__CONFIG(4,LVPDIS) ;
#define uint unsigned int
#define uchar unsigned char
#define bus RA4
#define nop NOP()
#define en RB3
#define rw RB4
#define rs RB5
#define D PORTD
unsigned char
unsigned char
//转换后的温度值小数点部分查表
const unsigned char tablexiao[16]={0,0,1,2,2,3,4,4,5,6,6,7,8,8,9,9};
char p[]="#@";
char k[]="kaito";
void delay(uint x)
{
int i,j;
for(i=0;i<=110;i++)
for(j=0;j<=x;j++);
}
void write_com(uchar com)
{
rs=0;
rw=0;
delay(5);
en=1;
delay(5);
D=com;
en=0;
delay(5);
}
void write_dat(uchar dat)
{
rs=1;
rw=0;
delay(5);
en=1;
delay(5);
D=dat;
en=0;
delay(5);
}
void init()
{
write_com(0x38);
write_com(0x0c);
write_com(0x06);
write_com(0x01);
}
void delayms(unsigned char x,unsigned char y)
{
unsigned char z;
}
uchar reset()
{
TRISA4=0;
bus=0;
delayms(10,25);
TRISA4=1;
delayms(5,1);
if(bus==1)
{
delayms(2,60);
return 0;
}
else
{
delayms(2,60);
return 1;
}
}
void write_byte(uchar dat)
{
uchar i;
for(i=0;i<8;i++)
{
TRISA4=0;
bus=0;
nop;
nop;
bus=dat&0x01;
delayms(5,3);
TRISA4=1; //释放总线
nop;
nop;
dat>>=1;
}
}
uchar read_byte()
{
uchar i,dat=0;
for(i=0;i<8;i++)
{
dat>>=1;
TRISA4=0;
bus=0;
nop;
nop;
nop;
nop;
nop;
TRISA4=1;
nop;
nop;
nop;
nop;
nop;
if(bus==1)dat=dat|0x80;
else dat=dat|0x00;
delayms(2,7); //这里延时时间略长可以使读数比较稳定
}
return dat;
}
void convert_T()
{
if(reset()==1)
{
write_byte(0x44);
}
}
void read_T(void)
{
{
temp2=Lsb&0x0f;
temp1=(Lsb>>4)|(Msb<<4);//LSB的高4位和MSB拼成整数部分
}
void main(void)
{
int i=0;
ADCON1=0X06;
TRISB=0B11000111;
TRISD=0x00;
init();
while(1)
{
convert_T();
read_T();
if(temp1>99) temp1=99; //这里我们只显示2位整数部分,所以限定在99度
if(temp2>15) temp2=0;
//下面就是用LCD1602显示
write_com(0x80+1);
write_dat(0x30+(temp1/10));
write_com(0x80+2);
write_dat(0x30+(temp1));
write_com(0x80+3);
write_dat('.');
write_com(0x80+4);
write_dat(0x30+tablexiao[temp2&0x0f]);
if(temp1>=23)
{
write_com(0x80+0x40+8);
write_dat('*');
write_dat('o');
write_dat('*');
write_dat('!');
}
else
{
write_com(0x80+0x40+8);
write_dat('=');
write_dat('v');
write_dat('=');
write_dat('?');
}
write_com(0x80+0x40+2);
for(i=1;i<=strlen(k);i++)
{
write_dat(*(k+i-1));
}
}
}