嵌入式MCU系统

来源:互联网 发布:iphone魔术软件 编辑:程序博客网 时间:2024/05/24 05:08
#include <stdlib.h>
#include <math.h>
#include <STC12C5A.h>
#include <intrins.h>
#include <Ctype.h>
#include "12864-T-H.h"
#include "IAP.h"


int main(void)
{
  WDT_CONTR = 0x3d;//看门狗定时器溢出时间2.2755s
  Init_lcd();
  while (1)
  {
  if ((code0==1) && (code1==1))
{
        Clear_lcd();
Sys_init1();
Fixed_disp1();
while (1)
{
       WDT_CONTR = 0x3d;
if (!flag2)
{
Humid_display();
if (update)
{
update = 0;
Buf_dispose();
Freq_dispose();
}
if (!flag1) Dispose_temp();
else Cel_TO_Fah();
}
else Set_disp();
if (f10ms)
{
f10ms = 0;
Humid_get();
timing();
Get_temp();
Tem_set();
if (temp1 > T_save)alert = 0;
else alert = 1;
}
   if (!((code0==1) && (code1==1))) break;
}
}
  if ((code0==0) && (code1==1))
{
        Clear_lcd();
Sys_init2();
Fixed_disp2();
while (1)
{
WDT_CONTR = 0x3d;
Pulse_creation();
//while (TH1 < 30);
//TR1 = 0;
//EX1 = 0;
//Distance_get();
Distance_dis();
Delay(540);
if (!((code0==0) && (code1==1))) break;
}
}
  if ((code0==1) && (code1==0))
{
        Clear_lcd();
Sys_init3();
HC595_init();
while (1)
{
WDT_CONTR = 0x3d;
Key_scan();
Key_dispose();
if (!((code0==1) && (code1==0))) break;
}
}
if ((code0==0) && (code1==0))
{
Clear_lcd();
Sys_init4();
Fixed_disp4();
while (1)
{
WDT_CONTR = 0x3d;
Speed_capture();
Speed_disp1();
Speed_disp2(30);
if (!((code0==0) && (code1==0))) break;
}
}
  }
return 0;
}


//固定显示
void Fixed_disp1(void)
{
Disp_8x16(1, 1, F);
Disp_8x16(1, (8+1), colon);
Disp_8x16(1, (8*2+1), num0);
Disp_8x16(1, (8*3+1), num0);
Disp_8x16(1, (8*4+1), num0);
Disp_8x16(1, (8*5+1), num1);
Disp_8x16(1, (8*6+1), K);
Disp_8x16(1, (8*7+1), H);
Disp_8x16(1, (8*8+1), z);
Disp_16x16(4, 1, bu);
Disp_16x16(4, (16*1+1), jin);
Disp_8x16(4, (16*2+1), colon);
Disp_8x16(4, (16*2+8*1+1), num0);
Disp_8x16(4, (16*2+8*2+1), num0);
Disp_8x16(4, (16*2+8*3+1), num0);
Disp_8x16(4, (16*2+8*4+1), num1);
Disp_8x16(4, (16*2+8*5+1), K);
Disp_16x16(4, (16*2+8*5+24+1), tri1);
Disp_16x16(4, (16*2+8*5+40+1), tri2);
Disp_8x16(7, (8*1+1), colon);
Disp_8x16(7, (8*7+16+8*2+1), H);
Disp_8x16(7, (8*7+16+8*3+1), colon);
Disp_8x16(7, (8*7+16+8*6+1), ratio);
Disp_8x16(1, (8*13+1), colon);
Disp_8x16(7, (8*5+1), dot);
}


//单片机初始化1
void Sys_init1(void)
{
T_save = Iap_read(IAP_ADDRESS);//初始化时首先将存于EEPROM中第一个扇区地址为IAP_ADDRESS中的温度报警值取出
led = 0;
ET1 = 0;
EX1 = 0;//先关闭外部中断
P1M1 = 0x00;
P1M0 = 0xfe;//推挽输出
P2M1 = 0x00;
P2M0 = 0x01;
P0M1 = 0x00;
P0M0 = 0x01;
EA = 1;
ET0 = 1;
AUXR = 0x80;//定时器时钟1T模式
TMOD = 0x21;//设置定时器模式
TL0 = 0xd7;//设置定时初值,定时50us
TH0 = 0xfd;
TF0 = 0;//清除TF0标志
TR0 = 1;//定时器0开始计时
SCON = 0x40;//串口工作在方式1:10位异步收发
PCON = 0x80;
TH1 = 0xFD;
TL1 = 0xFD;//波特率9600
TR1 = 1;
ES = 1;//开串口中断
REN = 1;//串口接收使能
IT0 = 1;//外部中断0为下降沿触发
P1ASF = 0x01;//P1^0作为湿度模拟信号入口
ADC_CONTR = 0xc0;
_nop_();
_nop_();
_nop_();
_nop_();
    AUXR1 = 0x00;
}


//接收数据处理函数
void Buf_dispose(void)
{
if ((buf1==0) && (buf0==0))
{
Disp_16x16(4, (16*2+8*5+24+1), tri1);
   Disp_16x16(4, (16*2+8*5+40+1), tri2);
}
if ((buf1==0) && (buf0==1))
{
Disp_16x16(4, (16*2+8*5+24+1), squ1);
   Disp_16x16(4, (16*2+8*5+40+1), squ2);
}
if ((buf1==1) && (buf0==0))
{
Disp_16x16(4, (16*2+8*5+24+1), sin1);
   Disp_16x16(4, (16*2+8*5+40+1), sin2);
}
if ((buf3==0) && (buf2==0))
{
Disp_8x16(4, (16*2+8*1+1), num0);
Disp_8x16(4, (16*2+8*2+1), num0);
Disp_8x16(4, (16*2+8*3+1), num0);
Disp_8x16(4, (16*2+8*4+1), num1);
step = 1;
}
if ((buf3==0) && (buf2==1))
{
Disp_8x16(4, (16*2+8*1+1), num0);
Disp_8x16(4, (16*2+8*2+1), num0);
Disp_8x16(4, (16*2+8*3+1), num1);
Disp_8x16(4, (16*2+8*4+1), num0);
step = 10;
}
if ((buf3==1) && (buf2==0))
{
Disp_8x16(4, (16*2+8*1+1), num0);
Disp_8x16(4, (16*2+8*2+1), num1);
Disp_8x16(4, (16*2+8*3+1), num0);
Disp_8x16(4, (16*2+8*4+1), num0);
step = 100;
}
if ((buf3==1) && (buf2==1))
{
Disp_8x16(4, (16*2+8*1+1), num1);
Disp_8x16(4, (16*2+8*2+1), num0);
Disp_8x16(4, (16*2+8*3+1), num0);
Disp_8x16(4, (16*2+8*4+1), num0);
step = 1000;
}
//if (FREQ >= step)
//{
if ((buf5==0) && (buf4==0))FREQ = FREQ + step;
if ((buf5==0) && (buf4==1)) FREQ = FREQ - step;

buf5 = 1;
if (FREQ > 6000) FREQ = 6000;
if (FREQ < 1) FREQ = 1;
}


//频率显示处理函数
void Freq_dispose(void)
{
uchar a = FREQ/1000;
uchar b = FREQ%1000/100;
uchar c = FREQ%1000%100/10;
uchar d = FREQ%1000%100%10;
Choose1(1, a, 2);
Choose1(1, b, 3);
Choose1(1, c, 4);
Choose1(1, d, 5);
}


//选择函数,u-行位置,v-要显示的数字,w-列位置
void Choose1(uchar u, uchar v, uchar w)
{
switch (v)
{
case 0: Disp_8x16(u, (8*w+1), num0); break;
case 1: Disp_8x16(u, (8*w+1), num1); break;
case 2: Disp_8x16(u, (8*w+1), num2); break;
case 3: Disp_8x16(u, (8*w+1), num3); break;
case 4: Disp_8x16(u, (8*w+1), num4); break;
case 5: Disp_8x16(u, (8*w+1), num5); break;
case 6: Disp_8x16(u, (8*w+1), num6); break;
case 7: Disp_8x16(u, (8*w+1), num7); break;
case 8: Disp_8x16(u, (8*w+1), num8); break;
case 9: Disp_8x16(u, (8*w+1), num9); break;
default:                             break;
}
}


//延时500us,对于传统51Delaynus(1)约7us,对于STC12则为约1us
void Delaynus(uint t)
{
while (--t);
}


//湿度转换结果处理
void Humid_get(void)
{
if (ad_count)
{
temp = ad_count%3;
if (temp == 1)
{
ad_sum += ADC_RES;
}
ADC_CONTR = 0xc8;//湿度AD转换
}
ad_count++;
if(ad_count>99)//1S对湿度值储存一次
{
ad_count = 1;
ad_sum += 16;//结果校正
ad_sum /= 33;
if (ad_sum < 63)
humid = 99;
else if (ad_sum < 68)
humid = 95;
else if (ad_sum < 73)
humid = 90;
else if (ad_sum < 78)
humid = 85;
else if (ad_sum < 83)
humid = 80;
else if (ad_sum < 88)
humid = 75;
else if (ad_sum < 93)
humid = 70;
else if (ad_sum < 98)
humid = 65;
else if (ad_sum < 103)
humid = 60;
else if (ad_sum < 108)
humid = 55;
else 
humid = 50;
ad_sum = 0;
}



//定时子函数
void timing(void)
{
if (spill)
{
if(humid >= humid_set)//湿度>设定值,倒计时
{
min = time_set;
sec = 60;
}
}
if (min)
{
   ms10++;
   if (ms10 > 60)
{
ms10 = 1;//重新计数
sec--;
}
if (sec == 0)
{
sec = 60;
min--;
}
led = 1;
spill = 0;
}
else//当倒计时结束时关闭继电器
{
sec = 0;
min = 0;
spill = 1;
led=0;
}
}


//湿度结果显示以及定时显示函数
void Humid_display(void)
{
uchar a = min;
uchar b = sec/10;
uchar c = sec%10;
uchar d = humid/10;
uchar e = humid%10;
switch (a)
{
case 0: Disp_8x16(1, (8*12+1), num0); break;
case 1: Disp_8x16(1, (8*12+1), num1); break;
case 2: Disp_8x16(1, (8*12+1), num2); break;
case 3: Disp_8x16(1, (8*12+1), num3); break;
case 4: Disp_8x16(1, (8*12+1), num4); break;
case 5: Disp_8x16(1, (8*12+1), num5); break;
default:                              break;
}
switch (b)
{
case 0: Disp_8x16(1, (8*14+1), num0); break;
case 1: Disp_8x16(1, (8*14+1), num1); break;
case 2: Disp_8x16(1, (8*14+1), num2); break;
case 3: Disp_8x16(1, (8*14+1), num3); break;
case 4: Disp_8x16(1, (8*14+1), num4); break;
case 5: Disp_8x16(1, (8*14+1), num5); break;
case 6: Disp_8x16(1, (8*14+1), num6); break;
default:                              break;
}
Choose1(1, c, 15);
switch (d)
{
case 4: Disp_8x16(7, (8*13+1), num4); break;
case 5: Disp_8x16(7, (8*13+1), num5); break;
case 6: Disp_8x16(7, (8*13+1), num6); break;
case 7: Disp_8x16(7, (8*13+1), num7); break;
case 8: Disp_8x16(7, (8*13+1), num8); break;
case 9: Disp_8x16(7, (8*13+1), num9); break;
default:                              break;

switch (e)
{
case 0: Disp_8x16(7, (8*14+1), num0); break;
case 5: Disp_8x16(7, (8*14+1), num5); break;
default:                              break;
}  
}


//18B20初始化操作
void Init_18B20(void)
{
DQ = 1;
Delaynus(10);
DQ = 0;
Delaynus(550);
DQ = 1;
Delaynus(230);
}


//18B20读操作
uchar Read_18B20(void)
{
uchar i = 0;
uchar dat = 0;
for (i=8; i>0; i--)
{
DQ = 0;
Delaynus(2);
dat >>= 1;
DQ = 1;
Delaynus(10);
if (DQ)
{
dat |= 0x80;
}
Delaynus(70);
}
return (dat);
}


//18B20写操作
void Write_18B20(uchar dat)
{
uchar i = 0;
for (i=8; i>0; i--)
{
DQ = 0;
Delaynus(2);
DQ = dat&0x01;
   Delaynus(70);
DQ = 1;//写完必须释放
dat >>= 1;
Delaynus(10);
}
}


//获取温度值
void Get_temp(void)
{
//float t = 0.0
uchar t = 0;
uint tt = 0;
uchar tem = 0;
uchar a = 0;
uchar b = 0;
Init_18B20();
Write_18B20(0xcc);//跳过ROM
Write_18B20(0x44);//温度转换
//Delay(200);
Init_18B20();
Write_18B20(0xcc);
Write_18B20(0xbe);//读暂存器
a =  Read_18B20();//第一个字节为LSB
b =  Read_18B20();//第二个字节为MSB
    tt = b;
tt <<= 8;
tt = tt|a;
t = tt>>4;
tem = 2+5*tt;
tem = tem>>3;
temp1 = t;
temp2 = tem%1000%100%10;//强制类型转换得到小数值
}


//温度显示处理函数
void Dispose_temp(void)
{
uchar i = temp1%100/10;
uchar j = temp1%100%10;
uchar k = temp2;
/*if (temp1/100 == 1)
Disp_8x16(7, (8*2+1), num1);
else
   Disp_8x16(7, (8*2+1), num0);*/
Disp_8x16(7, 1, T);
Disp_8x16(7, (1+4*8), dot);
Disp_16x16(7, (8*6+1), cent);
Choose1(7, i, 2);
Choose1(7, j, 3);
Choose1(7, k, 5);
}


//摄氏温度转换成华氏温度显示
void Cel_TO_Fah(void)
{
uchar i = fahrenheit/100;
uchar j = fahrenheit%100/10;
uchar k = fahrenheit%100%10;
fahrenheit = temp1*9/5+32;
Disp_8x16(7, 1, F);
Disp_8x16(7, (1+16), num0);
Choose1(7, i, 3);
Choose1(7, j, 4);
Choose1(7, k, 5);
Disp_16x16(7, (8*6+1), fa);
}


//向液晶写命令
void Write_lcd_com(uchar com)
{
uchar i;
uchar scom = com;
CS = 0;
RS = 0;
for (i=0; i<8; i++)
{
SCLK = 0;
if (scom & 0x80)
SDA = 1;
else
SDA = 0;
SCLK  = 1;
scom <<= 1;
}
}


//向液晶写数据
void Write_lcd_dat(uchar dat)
{
uchar i;
uchar sdat = dat;
CS = 0;
RS = 1;
for (i=0; i<8; i++)
{
SCLK = 0;
if (sdat & 0x80)
SDA = 1;
else 
SDA = 0;
sdat <<= 1;
SCLK = 1;
}
}


void Delay(uint t)
{
      uchar col;
 uchar row;
      while (t--)
 {
        for (col = 10; col>0; col--)
{
          for (row = 0; row<169; row++);
}
 }
}


//液晶初始化函数
void Init_lcd(void)
{
CS = 0;
RESET = 0;//低电平先复位液晶
Delay(20);
RESET = 1;//复位完毕可正常操作
Delay(20);
Write_lcd_com(0xe2);//由时序图先进行软复位
Delay(5);
Write_lcd_com(0x2c);//升压步骤1
Delay(5);
Write_lcd_com(0x2e);//升压步骤2
Delay(5);
Write_lcd_com(0x2f);//升压步骤3
Delay(5);
Write_lcd_com(0x23);//粗调对比度,可设置范围0x20-0x27
Write_lcd_com(0x81);//微调对比度
Write_lcd_com(0x28);//
Write_lcd_com(0xa2);//1/9偏压比
Write_lcd_com(0xc8);//行扫描顺序:上到下
Write_lcd_com(0xa0);//列扫描顺序:左到右
Write_lcd_com(0x40);//起始行:第一行
Write_lcd_com(0xaf);//开显示
CS = 1;
}


//设置显示地址
void Lcd_address(uchar page, uchar colum)
{
CS = 0;
colum = colum-1;
page = page-1;
Write_lcd_com(0xb0 + page);
Write_lcd_com(((colum>>4) & 0x0f) +0x10);
Write_lcd_com(colum & 0x0f);//设置列地址的低四位
}


//清屏函数
void Clear_lcd(void)
{
uchar i, j;
CS = 0;
for (i=0; i<9; i++)
{
Lcd_address(1+i, 1);
for (j=0; j<132; j++)
{
Write_lcd_dat(0x00);
}
}
CS = 1;
}


///显示 16x16 点阵图像、汉字、生僻字或其他图标
void Disp_16x16(uchar page, uchar colum, uchar *ptr)
{
uchar i, j;
CS = 0;
for (j=0; j<2; j++)
{
Lcd_address(page+j, colum);
for (i=0; i<16; i++)
{
Write_lcd_dat(*ptr);
ptr++;
}
}
CS = 1;
}


//显示 8x16 点阵图像、汉字、生僻字或其他图标
void Disp_8x16(uchar page, uchar colum, uchar *ptr)
{
uchar i, j;
CS = 0;
for (j=0; j<2; j++)
{
Lcd_address(page+j, colum);
for (i=0; i<8; i++)
{
Write_lcd_dat(*ptr);
ptr++;
}
}
CS = 1;
}


//IAP无操作
void Iap_idle(void)
{
IAP_CONTR = 0;
IAP_CMD = 0;
IAP_TRIG = 0;
IAP_ADDRH = 0x80;
IAP_ADDRL = 0;
}


//IAP读操作
BYTE Iap_read(WORD addr)
{
BYTE dat;//数据缓存
IAP_CONTR = ENABLE_IAP;
IAP_CMD = CMD_READ;
IAP_ADDRL = addr;
IAP_ADDRH = addr>>8;
IAP_TRIG = 0x5a;
IAP_TRIG = 0xa5;
_nop_();
dat = IAP_DATA;
Iap_idle();
return dat;
}


//IAP写操作
void Iap_programbyte(WORD addr, BYTE dat)
{
IAP_CONTR = ENABLE_IAP;
IAP_CMD = CMD_PROGRAM;
IAP_ADDRL = addr;
IAP_ADDRH = addr>>8;
IAP_DATA = dat;
IAP_TRIG = 0x5a;
IAP_TRIG = 0xa5;
_nop_();
Iap_idle();
}


//IAP扇区擦除
void Iap_erase(WORD addr)
{
IAP_CONTR = ENABLE_IAP;
IAP_CMD = CMD_ERASE;
IAP_ADDRL = addr;
IAP_ADDRH = addr>>8;
IAP_TRIG = 0x5a;
IAP_TRIG = 0xa5;
_nop_();
Iap_idle();
}


//IAP报警温度设定
void Tem_set(void)
{
if (setsave == settemp)
{
setms10++;
if (setms10 > 4)
{
setms10 = 5;
setnow = setsave;
}
}
else 
{
setms10 = 0;
setsave = settemp;
}
if (setnow != setbefore)
{
if (setnow == 0xfe)//设置报警温度按键按下
{
flag2++;
if (flag2 > 1)flag2 = 0;
}
if (flag2)
{
if (setnow == 0xfd)//报警温度递增按键按下
{
T_save++;
if (T_save > 50)//报警温度设置范围20℃到50℃
T_save = 20;
}
}
else//再次按下报警温度设置键,将设置的温度保存到EEPROM的地址IAP_ADDRESS中去
{
Iap_erase(IAP_ADDRESS); 
Iap_programbyte(IAP_ADDRESS, T_save);
}
if (setnow == 0xfb)//切换摄氏与华氏的按键按下
{
flag1++;
if (flag1 > 1)flag1 = 0;
}
if (setnow == 0xf7)  flag3 = 1;//掉电模式按键按下
}
if (flag3)
{
f50ms++;
if (f50ms > 5)//延时50ms再进入掉电模式,也是为了消除按键抖动
{
Clear_lcd();
flag3 = 0;
f50ms = 0;
EX0 = 1;//开外部中断0
PCON = 0x02;//进入掉电模式,从掉电模式唤醒后程序接着从此处往下执行
_nop_();
Reset();
}
}
setbefore = setnow;
}


//设置时的屏幕显示
void Set_disp(void)
{
uchar i = T_save/10;
uchar j = T_save%10;
Disp_8x16(7, 1, T);
Disp_8x16(7, (1+16), num0);
Disp_8x16(7, (1+24), num0);
Choose1(7, i, 4);
Choose1(7, j, 5);
Disp_16x16(7, (6*8+1), cent);
}


//软件复位
void Reset(void)
{
((void(code*)(void))0x0000)();//制地址指针指向程序开头0x0000地址处
}


//定时器0中断服务函数
void T0(void) interrupt 1 using 0
{
settemp = 0xff;
TR0 = 0;
TF0 = 0;
pwm++;
tim++;
if(tim >= 200)//连续读取处理40次湿度信号需要10X500us=5ms,然后在main()中进入if(f10ms)
{
  tim = 0;
  f10ms = 1;
}
if (pwm <= 9)
humi = 1;
else 
humi = 0;
if (pwm >= 20)
pwm = 0;
if (!set)   settemp &= 0xfe;
else settemp &= 0xff;
if (!SDATA) settemp &= 0xfd;
else settemp &= 0xff;
if (!SCL)    settemp &= 0xfb;
else settemp &= 0xff;
if (!PDOWN) settemp &= 0xf7;
else            settemp &= 0xff;
TL0 = 0xd7;
TH0 = 0xfd;
TR0 = 1;
}


//串口中断函数
void uart(void) interrupt 4 using 1
{
if (RI)
{
RI = 0;
buf = SBUF;
update = 1;
}
}


//外部中断0服务子函数,将单片机从掉电模式下唤醒
void INT0(void) interrupt 0
{
EX0 = 0;//关闭外部中断
}


//单片机初始化
void Sys_init2(void)
{
REN = 0;
RI = 0;
P1M1 = 0x00;
P1M0 = 0xfe;//如果不设置成推挽输出那么12864的输入信号极易受干扰出现花屏或者白屏
TR0 = 0;//定时器0关闭
TR1 = 0;
succeed_flag = 0;
led = 0;
ET0 = 0;
//AUXR = 0x3f;//定时器0与定时器1均是12分频
TMOD = 0x11;//设置定时器模式
TL0 = 0x00;//设置计数初值
TH0 = 0x00;
TF0 = 0;//清除TF0标志
TL1 = 0x00;//设置计数初值
TH1 = 0x00;
TF1 = 0;//清除TF0标志
ultrasonicTX = 0;//先将脉冲输出引脚拉低
ultrasonicRX = 1;
EX1 = 0;//外部中断不使能
IT1 = 1;//外部中断1中断源为下降沿触发
EA = 1;
}


//脉冲生成函数
void Pulse_creation(void)
{
    /*EA = 0;//先关闭所有中断(以下屏蔽的方法经验证不可取) 
ultrasonicTX = 1;
Delay20us();
ultrasonicTX = 0;
    Delay20us();
    EA = 1;
TR0 = 1;
TH0 = 0;
TL0 = 0;
EX1 = 1;
Delay(1);//延时2ms
while (succeed_flag == 0)//等待回波引脚变高电平以引起中断
{
led = 0;
temp3++;
if (temp3 > 80)
{
temp3 = 0;
break;
}
distance_tem = 0;
}
while (succeed_flag == 1) 
{
temp4++;
if (temp4 > 10)
{
temp4 = 0;
break;
}
}
distance_dat = (OUT_H*256+OUT_L);//把高八位的数和第八位的数组合成一个数
//distance_dat = (distance_dat*0.347056-19)/20-4;//计算距离,把值送给变量用于显示
distance_dat = distance_dat*0.01735;
distance_tem = distance_dat;
succeed_flag = 0;
TR0 = 0;
TH0 = 0;
TL0 = 0;
EX1 = 0;*/
uchar i;
succeed_flag = 0;//清测量成功标志
IE1 = 0;
EA = 1;
TF0 = 0;
TF1 = 0;
ultrasonicTX = 1;
Delay20us();
ultrasonicTX = 0;
TH1 = 0x00;
TL1 = 0x00;
TR1 = 1;
for (i=0; i<10; i++)//防止回声干扰
{
Delay20us();
}
while (ultrasonicRX == 0)//如果长时间没有检测到回波,就跳出进行下一次测量
{
time++;
if (time > 540)
{
time = 0;
break;
}
}
TH0 = 0;
TL0 = 0;
TR0 = 1;
EA = 1;
EX1 = 1;
Delay(30);//等待下降沿中断以获取测量结果
if (succeed_flag == 1)
{
distance_dat0 = OUT0_H*256+OUT0_L;
distance_dat1 = OUT1_H*256+OUT1_L;
//distance_dat = (distance_dat1-distance_dat0)*0.173528;//转换成cm(这里将小数点左移一位便于将小数点后的一位显示出来,实际应该是乘与0.0173528)
//distance_dat = (distance_dat1-distance-dat0)*11/64;//进一步优化
distance_dat = (distance_dat1-distance_dat0)*11 >> 6;//最终优化后的算法,有误差,但是效率显著提升
distance_tem = distance_dat;
distance_tem -= 15;//距离补偿
//Distance_dis();
}
if (succeed_flag == 0)
{
distance_tem = 0;
led = 0;
//Distance_dis();
}
}


//测量结果处理函数(该屏蔽的方法不可取)
/*void Distance_get(void)
{
if (succeed_flag == 1)
{
distance_dat = OUT_H;
distance_dat <<= 8;
distance_dat = distance_dat|OUT_L;
distance_dat *= 12;//因为定时器为12分频
distance_dat /= 58;//微秒的单位除以58等于厘米,这是由公式Y米= (X秒*344)/2换算得来的
}
if (succeed_flag == 0)
{
distance_dat = 0;//没有回波则清零
}
    distance[ctrl1] = distance_dat;//将测量结果的数据放入缓冲区
    ctrl1++;
  if(ctrl1 == 3)
{
distance_dat = (distance[0]+distance[1]+distance[2]+distance[3])/4;
distance_tem = distance_dat;
if (distance_ply == distance_tem) ctrl2 = 0;
if (distance_ply != distance_tem) ctrl2++;
if (ctrl2 == 3)
{
ctrl2 = 0;
distance_ply = distance_tem;
}
ctrl1 = 0;
}
}*/


//测量结果显示函数
void Distance_dis(void)
{
uchar a = distance_tem/100;
uchar b = distance_tem%100/10;
uchar c = distance_tem%100%10;
Choose2(a, 5);
Choose2(b, 6);
Choose2(c, 8);
}


//选择函数
void Choose2(uchar i, uchar j)
{
switch (i)
{
case 0: Disp_8x16(4, (8*j+1), num0); break;
case 1: Disp_8x16(4, (8*j+1), num1); break;
case 2: Disp_8x16(4, (8*j+1), num2); break;
case 3: Disp_8x16(4, (8*j+1), num3); break;
case 4: Disp_8x16(4, (8*j+1), num4); break;
case 5: Disp_8x16(4, (8*j+1), num5); break;
case 6: Disp_8x16(4, (8*j+1), num6); break;
case 7: Disp_8x16(4, (8*j+1), num7); break;
case 8: Disp_8x16(4, (8*j+1), num8); break;
case 9: Disp_8x16(4, (8*j+1), num9); break;
default:                             break;
}
}


//精确延时20uS
void Delay20us()
{
uchar i;
_nop_();
i = 52;
while (--i);
}


//外部中断1服务子函数
void INT1(void) interrupt 2 using 2 
{
if ((code0==0) && (code1==1))
{
EA = 0;//相应中断后先关闭中断
EX1 = 0;//关闭外部中断
TR0 = 0;
led = 1;    
OUT0_H = TH0;//取出定时器的值
OUT0_L = TL0;//取出定时器的值 
OUT1_H = TH1;//取出定时器的值
OUT1_L = TL1;//取出定时器的值  
TH0 = 0;  
TL0 = 0;
TH1 = 0;
TL1 = 0;  
succeed_flag = 1;//成功测量的标志
/*IE1 = 0;//屏蔽的方法经试验不可取
TR0 = 0;
EX1 = 0;
EA = 0;
OUT_H = TH0;
OUT_L = TL0;
succeed_flag = 1;
led = 1;*/
}
if ((code0==0) && (code1==0))//切换到霍尔测速外中断服务子函数
{
//counter2 = 0;
TR0 = 1;
counter1++;
}



//固定显示
void Fixed_disp2(void)
{
Disp_16x16(4, 1, ju);
Disp_16x16(4, (16*1+1), li);
Disp_8x16(4, (16*2+1), colon);
Disp_8x16(4, (16*2+8*3+1), dot);
Disp_8x16(4, (16*2+8*5+1), c);
Disp_8x16(4, (16*2+8*6+1), m_0);
}


void Sys_init3(void)
{
    //com = 1;
REN = 0;
RI = 0;
//P2M1 = 0x08;
//P2M0 = 0x00;//P2^3为高阻输入
P1M1 = 0x00;
P1M0 = 0xfe;
EX1 = 0;//外部中断不使能
TR0 = 0;//定时器0关闭
TR1 = 0;
ET0 = 0;
ET1 = 1;
AUXR = 0x80;//定时器0与定时器1均是12分频
TMOD = 0x11;//设置定时器模式
TL1 = 0x00;//设置定时初值,定时1ms
TH1 = 0x28;
TF1 = 0;//清除TF1标志
TR1 = 1;//定时器1开始计时
EA = 1;
}


//595初始化函数
void HC595_init(void)
{
SDATA = 0;
SCL = 1;
LCL = 0;
}


//595发送数据
void SendData(uchar dat)
{
uchar i;
uchar sdat = dat;
for (i=0; i<8; i++)
{
if (sdat & 0x80)
SDATA = 1;
else
SDATA = 0;
sdat <<= 1;
SCL = 0;
_nop_();
_nop_();
SCL = 1;
_nop_();
_nop_();
}
LCL = 1;
_nop_();
_nop_();
LCL = 0;
}


//按键扫描
void Key_scan(void)
{
uchar i = 0;
//keytemp = 4;
if (!com)
{
i = codetemp&0xf0;
/*if (codetemp|0x7f == 0x7f)keytemp = 0;
//else  keytemp = 4;
if (codetemp|0xbf == 0xbf)keytemp = 1;
//else  keytemp = 4;
if (codetemp|0xdf == 0xdf)keytemp = 2;
//else  keytemp = 4;
if (codetemp|0xef == 0xef)keytemp = 3;
//else  keytemp = 4;*/
switch (i)
{
case 0x70: keytemp = 0;break;
case 0xb0: keytemp = 1; break;
case 0xd0: keytemp = 2; break;
case 0xe0: keytemp = 3; break;
default:                break;
}
old = 1 ;
new = 0;
}
}


//按键处理
void Key_dispose(void)
{
//按键去抖
/*if(keysave == keytemp)
{
keyms10++;
if(keyms10 >4)
{
keyms10 = 5;
key = keysave;//去抖动后记录按键有效值
}
}
else
{
keyms10 = 0;
keysave = keytemp;
}
key = keytemp;
//按键处理
if (key != keybefore)//短按生效
{
if (key == 0)
{
keymark = 0;
}
if (key == 1)
{
keymark = 1;
}
if (key == 2)
   {
keymark = 2;
}
if (key == 3)
{
keymark = 3;
}
    }
    keybefore = key;*/
if (old && (!new))
{
if (com)
{
old = 1;
new = 1;
switch (keytemp)
{
case 0: keymark = 0; break;
case 1: keymark = 1; break;
case 2: keymark = 2; break;
case 3: keymark = 3; break;
default :            break;
}
}
}
}


//定时器1中断服务子函数
void T1(void) interrupt 3  
{
    keytemp = 4;
TF1 = 0;
TR1 = 0;
TH1 = 0x28;
TL1 = 0x00;
count++;
//SDATA = 1;
if (count > 4)
{
count = 0;
//scan10ms = 1;
}
switch (count)
{
case 0: codetemp = codetemp|0xf0; codetemp = codetemp&0x7f; SendData(codetemp);  break;
case 1: codetemp = codetemp|0xf0; codetemp = codetemp&0xbf; SendData(codetemp);  break;
case 2: codetemp = codetemp|0xf0; codetemp = codetemp&0xdf; SendData(codetemp);  break;
case 3: codetemp = codetemp|0xf0; codetemp = codetemp&0xef; SendData(codetemp);  break;
case 4: switch (keymark)
{
case 0: codetemp = 0xf7; SendData(codetemp); break;
case 1: codetemp = 0xfb; SendData(codetemp); break;
case 2: codetemp = 0xfd; SendData(codetemp); break;
case 3: codetemp = 0xfe; SendData(codetemp); break;
default:                                     break;
}   break;
default:                                                                         break;
}
if (!com)
TR1 = 1;
}


/*******************************************/
/***以下是切换到霍尔测速以及PID控制的模块***/
/*******************************************/


//PID相关
/*struct pid{
float SetSpeed;//定义设定值
float ActualSpeed;//定义实际值
float err;//定义偏差值
float err_next;//定义上一个偏差值
float err_last;//定义最上前的偏差值
float Kp, Ki, Kd;//定义比例,积分,微分系数
}pid;*/


//系统初始化方案4
void Sys_init4(void)
{
REN = 0;//先关串口接收
RI = 0;
P1M1 = 0x00;
P1M0 = 0xfe;//如果不设置成推挽输出那么12864的输入信号极易受干扰出现花屏或者白屏
TR0 = 0;//定时器0关闭
TR1 = 0;
ET0 = 0;
AUXR = 0x80;//定时器0不分频
TMOD = 0x11;//设置定时器模式
TL0 = 0x00;//设置计数初值
TH0 = 0x00;
TF0 = 0;//清除TF0标志
ultrasonicRX = 1;//超声波接收与霍尔测速都是下降沿触发,而且复用了同一个端口INT0(ultrasonicRX)
EX1 = 1;//外部中断不使能
IT1 = 1;//外部中断1中断源为下降沿触发
EA = 1;
CCON = 0;//初始化PCA模块
CL = 0;
CH = 0;
CMOD = 0x0a;//输出频率=(SYSclk/256)/4 = 10.8KHz
CCAP0H = CCAP0L = 0x80;//输出占空比50%
    CCAPM0 = 0x42;//工作于8位PWM模式,无中断
CR = 1;//开PCA模块
}


//固定显示
void Fixed_disp4(void)
{
Disp_16x16(3, 1, mu);
Disp_16x16(3, (16*1+1), qian);
Disp_16x16(3, (16*2+1), zhuan);
Disp_16x16(3, (16*3+1), su);
Disp_8x16(3, (16*4+1), colon);
Disp_8x16(3, (8*7+16+8*4+1), R);
Disp_8x16(3, (8*7+16+8*5+1), P_0);
Disp_8x16(3, (8*7+16+8*6+1), M);
Disp_16x16(5, 1, qi);
Disp_16x16(5, (16*1+1), wang);
Disp_16x16(5, (16*2+1), zhuan);
Disp_16x16(5, (16*3+1), su);
Disp_8x16(5, (16*4+1), colon);
Disp_8x16(5, (8*7+16+8*4+1), R);
Disp_8x16(5, (8*7+16+8*5+1), P_0);
Disp_8x16(5, (8*7+16+8*6+1), M);
}


//霍尔测速
void Speed_capture(void)
{
uint speed0 = 0;
if (TF0 == 1)
{
TF0 = 0;
TH0 = 0;
TL0 = 0;
counter2++;
}
if (counter2 > 700) 
{
counter2 = 0;
speedtemp = 0;
}
if (counter1 == 8)
{
counter1 = 0;
TR0 = 0;//关计数器
speed0 = TH0*256+TL0;
TH0 = 0;
TL0 = 0;
//speedtemp = 10125/(counter2>>6);
speedtemp = 70876/(counter2+speed0/9362);
speed0 = 0;
counter2 = 0;
}
}


//当前速度显示
void Speed_disp1(void)
{
uchar i, j, k, l;
i = speedtemp/1000; 
j = speedtemp%1000/100;
k = speedtemp%1000%100/10;
l = speedtemp%1000%100%10;
Choose1(3, i, 9);
Choose1(3, j, 10);
Choose1(3, k, 11);
Choose1(3, l, 12);
//speedtemp = 0;
}


void Speed_disp2(uint speed)
{
uchar i, j, k, l;
i = speed/1000; 
j = speed%1000/100;
k = speed%1000%100/10;
l = speed%1000%100%10;
Choose1(5, i, 9);
Choose1(5, j, 10);
Choose1(5, k, 11);
Choose1(5, l, 12);
}
0 0