51单片机验证牛顿第二定律
- 运用定时器
- 外部中断
- lcd1602的 显示
- 数据的处理
#include<reg51.h>
#include<intrins.h>
#define uchar unsigned char
#define uint unsigned int
#define delayNOP(); {_nop_();_nop_();_nop_();_nop_();};
#define s 30
sbit led = P2^4;
sbit key1 = P1^7;
sbit key2 = P3^2;
sbit key3 = P3^0;
int count =0;
int str[3];
int m = 0;
int m1 = 0;
int flag = 0;
int flag1 = 0;
int temp = 0;
int temp1 = 0;
int t0;
int t2;
int t1;
int a ;
int v0;
int v1;
int v2;
int pp =0;
int pp1 = 0;
void data_deal();
/* 初始化定义引脚 */
sbit rs=P2^0;
sbit rw=P2^1;
sbit lcden=P2^2;
void Delay(uint num) //延时函数
{
while( --num );
}
void delay1(int ms)
{
unsigned char n;
while(ms--)
{
for(n = 0; n<250; n++)
{
_nop_();
_nop_();
_nop_();
_nop_();
}
}
}
/******** 1602的设置 ********/
void write_com(uchar com) //写指令
{
// while(lcd_busy());
rs = 0;
// LCD_RW = 0;
lcden = 0;
_nop_();
_nop_();
P0 = com;
delayNOP();
lcden = 1;
delayNOP();
lcden= 0;
Delay(10);
}
void write_date(uchar date) //写数据
{
// while(lcd_busy());
rs = 1;
// LCD_RW = 0;
lcden= 0;
P0 = date;
delayNOP();
lcden = 1;
delayNOP();
lcden= 0;
Delay(10);
}
void init1()
{
TMOD=0x10; //模式设置,00000001,可见采用的是定时器0,工作与模式1(M1=0,M0=1)。
TH1=(65536-46080)/256; //由于晶振为11.0592,故所记次数应为46080,计时器每隔50000微秒发起一次中断。
TL1=(65536-46080)%256; //46080的来历,为50000*11.0592/12
ET1=1; //开定时器0中断
EA=1; //开总中断
EX1 = 1;
IT1 = 1;
}
/**** 相关的初始化 ******/
void init()
{
TMOD=0x01; //模式设置,00000001,可见采用的是定时器0,工作与模式1(M1=0,M0=1)。
TH0=(65536-46080)/256; //由于晶振为11.0592,故所记次数应为46080,计时器每隔50000微秒发起一次中断。
TL0=(65536-46080)%256; //46080的来历,为50000*11.0592/12
ET0=1; //开定时器0中断
EA=1; //开总中断
EX0 = 1;
IT0 = 1;
}
void init_1602() //1602的初始化
{
rw = 0;
delay1(15);
write_com(0x01); //清除LCD的显示内容
write_com(0x38); //16*2显示,5*7点阵,8位数据
delay1(5);
write_com(0x38);
delay1(5);
write_com(0x38);
delay1(5);
write_com(0x0c); //开显示,不显示光标
delay1(5);
write_com(0x01); //清除LCD的显示内容
delay1(5);
}
/*** 显示处理 ****/
void display_xy(uchar x,uchar y)
{
if(y==0x01)
{
x = x + 0x40 + 0x80;
}
else
{
x = x+0x80; //数据指针设置 80H+地址码 (0-27H,40H-67H)
}
write_com(x);
}
void Disp1Char(uchar x,uchar y,uchar f_data)
{
display_xy(x,y);
write_date(f_data); ////输出数据
}
void Disp_float(uint f_data)
{
unsigned char lcd_table[3];
lcd_table[0]= f_data/100; //第一位
lcd_table[1]= f_data%100/10; //第二位
lcd_table[2]=f_data%100%10;
Disp1Char(3,0,(lcd_table[0]+0x30)); //显示整数部分的十位数 0x30的原因CGROM和CGRAM与字符的对应关系
Disp1Char(4,0,(0x2e)); //显示小数点"." 小数点对应00101110
Disp1Char(5,0,(lcd_table[1]+0x30));
Disp1Char(6,0,(lcd_table[2]+0x30)); //显示小数部分的个位
// Disp1Char(7,0,(lcd_table[3]+0x30));
//Disp1Char(8,0,(lcd_table[2]+0x30)); //显示小数部分的十分位
//加上0x30以便直接得到相应的ASCII码去显示
}
void Disp_float1(uint f_data)
{
unsigned char lcd_table[3];
lcd_table[0]= f_data/100; //第一位
lcd_table[1]= f_data%100/10; //第二位
lcd_table[2]=f_data%100%10;
Disp1Char(11,0,(lcd_table[0]+0x30)); //显示整数部分的十位数 0x30的原因CGROM和CGRAM与字符的对应关系
Disp1Char(12,0,(0x2e)); //显示小数点"." 小数点对应00101110
Disp1Char(13,0,(lcd_table[1]+0x30));
Disp1Char(14,0,(lcd_table[2]+0x30)); //显示小数部分的个位
}
void Disp_float2(uint f_data)
{
unsigned char lcd_table[3];
lcd_table[0]= f_data/100; //第一位
lcd_table[1]= f_data%100/10; //第二位
lcd_table[2]=f_data%100%10;
Disp1Char(3,1,(lcd_table[0]+0x30)); //显示整数部分的十位数 0x30的原因CGROM和CGRAM与字符的对应关系
Disp1Char(4,1,(0x2e)); //显示小数点"." 小数点对应00101110
Disp1Char(5,1,(lcd_table[1]+0x30));
Disp1Char(6,1,(lcd_table[2]+0x30)); //显示小数部分的个位
}
void Disp_float3(uint f_data)
{
unsigned char lcd_table[3];
lcd_table[0]= f_data/100; //第一位
lcd_table[1]= f_data%100/10; //第二位
lcd_table[2]=f_data%100%10;
Disp1Char(11,1,(lcd_table[0]+0x30)); //显示整数部分的十位数 0x30的原因CGROM和CGRAM与字符的对应关系
Disp1Char(12,1,(0x2e)); //显示小数点"." 小数点对应00101110
Disp1Char(13,1,(lcd_table[1]+0x30));
Disp1Char(14,1,(lcd_table[2]+0x30)); //显示小数部分的个位
}
void start_inter()
{
uint temp;
while(1 )
{
if(pp==20)
{
pp=0;
m++;
if(m==600)
{
m=0; //若到了600s,则归零
}
}
temp = m *100;
// Disp_float(temp);
if(flag == 1 && count == 1)
{
TR0 = 0; //关闭定时器
flag = 0;
t0 = temp;
break;
}
if(flag == 1 && count == 2){
TR0 = 0;
flag = 0;
t2 = temp;
data_deal();
break;
}
}
}
void data_deal()
{ //Disp_float1(t0);
// Disp_float2(t2);
//Disp_float(t0);
t1 = t2 -t0;
a = (2 * s*(2*t0 – t2)) /(t0*t2*(t2- t0));
v0 = (s -(a/2)*t0*t0)/t0;
v1 = v0 + a *t0;
v2 = v0 + a* t2;
Disp_float(v0);
Disp_float1(v1);
Disp_float2(v2);
Disp_float3(a);
}
void time0() interrupt 1
{
TH0=(65536-46080)/256;
TL0=(65536-46080)%256;
pp++;
}
void interrupt0() interrupt 0
{
//开外部中断0
if ( key2 == 0) //触发门外光控回路之前,没有触发门内的
{
count++;
flag = 1; //启动显示标志
}
}
int main()
{
// int t1;
// int t2;
init_1602();
// init();
Disp1Char(0,0,'v');
Disp1Char(1,0,'0'); //将第一个字符a(加速度)写在向右偏移1个字符处,为后面的由右向左划入做准备。
Disp1Char(2,0,'=');
// Delay(20);
Disp1Char(8,0,'v');
Disp1Char(9,0,'1'); //将第二个字符v(瞬时速度)写在向右偏移1个字符处,为后面的由右向左划入做准备。
Disp1Char(10,0,'=');
// Delay(20);
Disp1Char(0,1,'v');
Disp1Char(1,1,'2'); //将第三个字符t(时间)写在向右偏移1个字符处,为后面的由右向左划入做准备。
Disp1Char(2,1,'=');
Disp1Char(8,1,'a');
Disp1Char(9,1,'=');
// Delay(20);
//EA = 1; //开启串行口中断允许,开启外部中断0、外部中断1
//设置外部中断0、1为下降沿触发
while(1)
{
if(key1== 0 )
{
EA = 1;
TR0 = 1;
init();
start_inter();
if(flag == 1)
{
EX0 = 0;
EA=0;
}
}
// Disp_float3(str[0]);
//Disp_float2(str[1]);
;
}
return 0;
}