STC单片机单片机串口接收数据包之如何判断数据结束

STC12C5A60S2单片机串口接收数据_百度知道
STC12C5A60S2单片机串口接收数据
这个单片机接收一个连续的15字节的帧数据,使用定时器1波特率怎么设置呢?用了stc的例程或者网上的例程总是不对,要不就是12字节要不就13字节,收不到全的。
我有更好的答案
定时器1设置波特率,与接收多少个字节没有关系,接收一个,几百个,就是不停地接收,只要波特率不变,设置的时间常数就不用变。至于接收多少字节为一帧数据,也不是用定器1来控制来计数的,它只管波特率。要控制接收多少字节,用一个变量计数。对于这种按帧来发送/接收的数据包,都应该有一个起始字节(固定的特殊的字节),当接收到起始字节就开始计数,算起始字节共接收到15个,就设置一个标志位,表示一帧接收结束。然后主程序查询到标志位后进行执行处理。这种以帧为一个数据包字的节数也不是固定的,所以,网上的例程也不过是个例程而已,不是拿来就直接用的,需要根据实际做适当修改的。哪有什么都照搬的。
嗯,首先感谢你耐心的回答。然后反馈一下,修改后的程序现在波特率确定没问题了,我用单片机给PC段的助手发送字符串,通信无误了。但是上面的问题仍然存在,用助手收的话是15字节,用单片机是13字节。接收的数据是一串16进制数,就是说漏了2个字节,每次都是。既然波特率没问题,怎么会少这2个字节呢?会是什么原因呢?
你之前提问过,我想起来了。其实,这个问题,也好解决,先不管接收什么,也不管是什么数据,凡是收到一个字节就显示出来,用LCD1602两行足够显示的,就可以看到了,到底都收到什么数据了,到底还缺少什么字节了。既然串口助手收没有问题,那用单片机也一样,没有问题。
用1602显示十六进制数搞了好久没搞出来。
你既然用STC12C5A60S2,有两个串口,一个串口接收那个传感器的数据,用另一个串口按接收原数据发送出,再用电脑串口调试助手接看就方便多了,程序也好写。其实,问题也很好解决,就是你准备用那个传感器做什么,就直接写那个程序吗,接收到数据后打算做什么,就做什么呀,看能不能达到效果。既然LCD显示程序不会写,总不能就在这傻等吧。得想点办法吗。
采纳率:92%
为您推荐:
其他类似问题
stc12c5a60s2的相关知识
换一换
回答问题,赢新手礼包
个人、企业类
违法有害信息,请在下方选择后提交
色情、暴力
我们会通过消息、邮箱等方式尽快将举报结果通知您。网站已改版,请使用新地址访问:
uart 一个很好的单片机串口接收程序,可以把收 数据显示在LCD上面, SCM 开发 238万源代码下载- www.pudn.com
&文件名称: uart
& & & & &&]
&&所属分类:
&&开发工具: Visual C++
&&文件大小: 50 KB
&&上传时间:
&&下载次数: 61
&&提 供 者:
&详细说明:一个很好的单片机串口接收程序,可以把收到的数据显示在LCD上面,-A good single-chip serial receiver, received data can be displayed on the LCD above,
文件列表(点击判断是否您需要的文件,如果是垃圾请在下面评价投诉):
&&串口数据接收器&&..............\src&&..............\...\1602display.c&&..............\...\1602DISPLAY.h&&..............\...\main.c&&..............\uot&&..............\...\1602display.lst&&..............\...\1602display.obj&&..............\...\main.lst&&..............\...\main.obj&&..............\...\串口数据接收&&..............\...\串口数据接收.hex&&..............\...\串口数据接收.lnp&&..............\...\串口数据接收.m51&&..............\...\串口数据接收.plg&&..............\串口数据发送器&&..............\..............\main.c&&..............\..............\main.LST&&..............\..............\main.OBJ&&..............\..............\串口数据发送器&&..............\..............\串口数据发送器.hex&&..............\..............\串口数据发送器.lnp&&..............\..............\串口数据发送器.M51&&..............\..............\串口数据发送器.Opt&&..............\..............\串口数据发送器.plg&&..............\..............\串口数据发送器.uv2&&..............\..............\串口数据发送器_Opt.Bak&&..............\串口数据接收.DSN&&..............\串口数据接收.Opt&&..............\串口数据接收.PWI&&..............\串口数据接收.Uv2&&..............\串口数据接收_Opt.Bak&&..............\串口数据接收_Uv2.Bak
&[]:纯粹是垃圾
&近期下载过的用户:
&相关搜索:
&输入关键字,在本站238万海量源码库中尽情搜索:
&[] - 我用MSCOMM控件写的串口接收程序,成功使用。
&[] - 此程序是利用VC++实现PC机与单片机串口通信任务(方法1)
&[] - 单片机串口接收数据发送数据程序:一个经典的例子,值得大家参考和学习
&[] - STC单片机串口通信程序,控制16路VGA信号切换
&[] - 这是AVR系列单片机mega16串口的初始化程序和串口接收程序
&[] - 矩阵键盘程序,特别使用,msp430单片机的
&[] - 51单片机用1602液晶显示串口接收到的数据
&[] - UART串口程序,设置波特率和停止位、奇偶校验位等等,使能串口,数据进行发送与接收,再进行显示。还没有帐号? 赶紧
用户版块帖子
1到第8) ? 8 :
location='read.php?tid=1989314&page='+page+'';}">页8) ? 8 :
location='read.php?tid=1989314&page='+page+'';">确认
开水烫STC15W4K48S4,看看我的STC单片机是不是假的。(2-18 新增简易线性检测)
UID:813565
在线时间2266小时
M币3721专家193
本帖被 香瑶 设置为精华,作者+3000M币+5专家()
看论坛的贴,说STC单片机有假,AD采集跳动大,吓得我大吃一斤,我常用STC单片机制作一些小制作,常用它的AD,如有这些问题我的制作都有问题,也没注意过温度对它的影响,所以在这做一次温度对单片机AD采集的影响测试。看看我的STC单片机有没假。实验采用本人的STC15W4K48实验板,在AD0及AD1接电阻,对它进行连接采集或延时1ms或100ms进行采集,然后通过串口把数据送出来。并用DIY的下载器检测它的电流,看看温度对它的影响。实验板及电路图如下。 在这板增加下面几个元件,一个温度NTC 用于测试温度。以下是在背面焊这几个元件,NTC直接在单片机上,进行温度检测。以下是正常状态测试工作电流为0.02A用STC下载程序的串口助手接收数据以下是常温下用延时100ms采集,即每0.1S采集一次,由于STC下载软件看数据不方便,所以左则用TXT文档处理一下,就方便比较。串口输出的数据设置为:两个引导码,一个状态值,2位AD0的值(已转BCD),1位转换温度值,最后2位为AD1值。如下图:FF FF 02 04 63 20 05 19&& 对应为:两个引导码&&状态值为2,即延时0.1s(0为不延时,1为延时1ms),ad0的值为463,计算出的温度值为20度,AD1的值为519(由于是元件有误差,所以值不为512.)。延时1ms不延时以下3张图可以看出,AD1的值一直为518或519或520,跳动并不大,可以说基本没跳动。以下是用开水烫的测试,用塑料杯上开水,压住单片机及NTC。从下图可以看到,CPU的工作电流没变化。
[ 此帖被落叶风在 18:16重新编辑 ]
本文内容包含图片或附件,获取更多资讯,请
后查看;或者
成为会员获得更多权限
UID:813565
在线时间2266小时
M币3721专家193
以下三张图为上开水烫时输出的数据,可以看出水的温度不太高,大约60度左右,从表中看,ad1的值基本没跳动,只不过比常温的值高了,常温AD1的采集值为519,开水烫的值为520 查STC的手册,它说经175度8小时烤,我也试试用烙铁烤。 把烙铁调到200度,这个是最低的温度了。
压住NTC及单片机。 以下为串口发出的数据,由于程序最大温度值为99度,已超出来,所以显示99度,对这个温度看输出发现有在519及520间跳动。
根据以上的测试,可以说明我的stc15w4k48的单片机是真货。
**************************************的新内容&& ********************************************&&&&由于在本贴有坛友跟贴说STC单片机AD的线性不好,(说测工作电源电压,外挂431,4.5v时显示3v,5v时显示5.3v,5.3v时显示8v),这个也相差得太大了。由于在家无聊,所以找些东西出来简单测试一下,所以在这加几张图,说一说本人测试的情况。发贴只是本人的使用的实际情况,实事求事,不针对什么人和事的。&& 由于早期的STC单片机内是没有基准的,所以一般是用外接TL431,通过TL431的值,反算出单片机供电电压。由于本人是简单测试,没有找旧版的STC单片机,而是用新的STC15W408AS单片机,它里内带有基准电压的,通过测试内部基准,可以算出单片机的供电电压,我在这是用带电压电流表的多功能STC免冷启动自动下载器http://bbs.mydigit.cn/read.php?tid=1984746,它带有单片机的供电电压值显示,是通过检测内部基准的值算出来的。以下是测试的图片。 由于STC15W408AS可在3.3V电压工作,但由于OLED是接了个3.3V的低压差的稳压,所以供电不能太低,所以在这以4V供电开始试。找出另一个多用工具组合,设置它的电源电源输出为4V,由于校准没做好,显示为3.9V。接USB接口,从USB接口有夹夹住,接万用表对比测试。以下是4V供电。以下是放大图,看下载器的CPU电压值,这个是单片机的供电电压,维修电源提供4V供电,可以看到单片机的供电电压为4.02V,万用表的电压为4.01V,差不多。 以下为4.5V的供电图 放大后可以看到电压与万用表一样。 以下为5V对比 以下为5.4V的对比较图
由于只是简单测试,没有进行从0到VCC进行多个电压值的读取比较,所以这个测试不能完整反映它的线性情况。*************************************新内容结束************************************************ 以下是AD测试的程序。程序只对AD0AD1进行采集,AD0接温度电阻,主要是看AD1的值。把数据通过串口送出。P33 P34分别对地就会启动延时采集。 //AD测试,单片机 STC15W4K48S,频率22.1184M//主要测试温度对AD的影响,数据用串口输出,AD0上接10KNTC电阻,下接10K电阻,AD1上下接10K电阻。//先是引导码FF FF ,接住为延时时间(0为不延时,1为延1ms,2为延100ms),//接住为AD0的值,占2位显示,分别为千百十个(已转BCD,方便看),//接住是计算出来的温度值,接住为AD1的值.//如:FF FF 00 04 70 21 05 06,表示不延时,AD0值为470,计算出来的温度为21度,AD1的值为506.#include &STC15W4Kxx.h&sbit kkk1=P3^3;sbit kkk2=P3^4;unsigned int code temppiao[]={//NTC温度下拉10K电阻对应的取样值表。&&&&189,196,204,212,219,227,236,244,252,261,//-10--1&&269,278,287,296,305,314,322,331,340,350,//0-9&&359,360,364,371,379,390,401,413,426,438,//10-19&&451,464,477,489,501,512,523,534,544,554,//20-29&&564,573,583,592,600,609,618,626,634,643,//30-39&&651,659,667,675,683,691,698,706,713,721,//&&728,735,742,749,756,763,770,777,784,791,//&&798,801,805,809,814,819,824,829,834,839,//&&844,849,853,858,862,866,870,874,877,881,//&&884,887,890,893,895,898,901,904,906,909,//&&911,914,917,919,922,925,927,930,933,935,//90-99&&&&};void delay(unsigned int t) //长延时程序,延时t毫秒,STC 1T单片机11.0592M晶振I值为648,22.1I值为1298,12MI值为705,27.648M I值为1622。{&&&&&&&& while(t--)&&&&&& {&&&&&&&&for(i=1298;i&0;i--);&&&&&& }}void rs1_232tx(unsigned char txdata){&&&& SBUF=//把数据传给串口寄存器SBUF。&&&& while(!TI);//检测是否发完。&&&& TI=0;//重置初值。}//以下为AD检测void ADCINT(){&& P1ASF=0//设置 P1低2位为AD口,根据实际设置。&& ADC_RES=0;//ad清0&& //AUXR1=0x04;//设置数据方式,低8位+高2位方式,易于运算204E的写法。&& CLK_DIV=0X20;//设置数据方式,低8位+高2位方式,408AS写法。&&&&delay(1);} unsigned int ADCwrite(unsigned ch){ //由于所检测的电压不用快,所以采用查询或延时法,没用中断法。 ch值从0-7,对应为P10-P17&&&&&&&&ADC_CONTR=0x88+//设置启动 ,用慢速采集&&&&//查询法。查询是否完成AD,由于是单片机内的,如出错单片机也出错,所以没做跳开处理。&&&&while ( !(ADC_CONTR & 0x10) );//等待A/D转换结束(ADC_FLAG==0)&&&&ADC_CONTR &= 0xE7;&&&&&&&&&&&& //,置ADC_FLAG=0清除结束标记, 置ADC_START=0关闭A/D 转换&&&&&&&&//delay(1);//延时法。由于设置及晶振的原因,大约为20US完成过程。这里延时1MS&&x=ADC_RES*256+ADC_RESL;&&} void UartInit1(void)&&&&&&&&//19200bps@22.1184MHz{&&&&SCON = 0x50;&&&&&&&&//8位数据,可变波特率&&&&AUXR |= 0x40;&&&&&&&&//定时器1时钟为Fosc,即1T&&&&AUXR &= 0xFE;&&&&&&&&//串口1选择定时器1为波特率发生器&&&&TMOD &= 0x0F;&&&&&&&&//设定定时器1为16位自动重装方式&&&&TL1 = 0xE0;&&&&&&&&//设定定时初值&&&&TH1 = 0xFE;&&&&&&&&//设定定时初值&&&&ET1 = 0;&&&&&&&&//禁止定时器1中断&&&&TR1 = 1;&&&&&&&&//启动定时器1 &&&&//ES=1;//开中断} void main(void){&&&&unsigned int AD&&&&&&&&P1M0=0;&&&&P1M1=0//AD为高阻&&&&UartInit1();&&&&ADCINT();&&while(1)&&{&&&&&&&&if(kkk1==0)delay(1);//判断P33是否接地,如接为延时1ms&&&&&&&&if(kkk2==0)delay(100);//判断P34是否接地,如接为延时100ms,如两者都没接地为不延时。&&&&&&&&//发送2个区分码&&&&&&&&rs1_232tx(0xff);&&&&&&&&rs1_232tx(0xff);&&&&&&&&//发送状态值&&&&&&&&if(kkk1==1&&kkk2==1)rs1_232tx(0);&&&&&&&&if(kkk1==0)rs1_232tx(1);&&&&&&&&if(kkk2==0)rs1_232tx(2);&&&&&&&&//采集AD0,并发送,转成BCD方式&&&&&&&&ADvol=ADCwrite(0);&&&&&&&&rs1_232tx((ADvol/1000)*16+ADvol%);&&&&&&&&rs1_232tx((ADvol%100/10)*16+ADvol%10);&&&&&&&&//计算AD0对应的温度值并发送&&&&&&&&for(x=0;x&110;x++)//查表计算室温&&&&&&&&{&&&&&&&&if( (ADvol)&=temppiao[x])//并且退出查表 &&&&&&&&}&&&&&&&&ADvol=x-11;&& rs1_232tx((ADvol/10)*16+ADvol%10);&&&&&&&&//采集AD1的值并发送,转成BCD码。&&&&&&&&ADvol=ADCwrite(1);&&&&&&&&rs1_232tx((ADvol/1000)*16+ADvol%);&&&&&&&&rs1_232tx((ADvol%100/10)*16+ADvol%10); } }
[ 此帖被落叶风在 18:04重新编辑 ]
本文内容包含图片或附件,获取更多资讯,请
后查看;或者
成为会员获得更多权限
UID:1758977
在线时间235小时
M币4810专家9
楼主的单片机看来是真的
UID:1945833
在线时间234小时
M币994专家7
发发我的吧!对了,STC是经过两级稳压,电压一直再4.97左右,极为稳定,AMS1117的功力可信。
本文内容包含图片或附件,获取更多资讯,请
后查看;或者
成为会员获得更多权限
UID:1945833
在线时间234小时
M币994专家7
LZ的开发板做的不错,可是为何不镀锡?时间久了,MCU的细走线容易蚀断,通过照片隐约看出已经有略微氧化腐蚀。
UID:1274537
在线时间656小时
M币619专家1
同感,最近在淘宝买了个STC15W408AS,timer1死活打不开(用官网的测试程序也不行)
UID:813565
在线时间2266小时
M币3721专家193
回 skw168 的帖子
:同感,最近在淘宝买了个STC15W408AS,timer1死活打不开(用官网的测试程序也不行) ( 11:16) 详细看官方手册吧,这个型号的单片机没时钟1的,只有时钟0及2.[ 此帖被落叶风在 11:38重新编辑 ]
本文内容包含图片或附件,获取更多资讯,请
后查看;或者
成为会员获得更多权限
UID:1945833
在线时间234小时
M币994专家7
回 skw168 的帖子
:同感,最近在淘宝买了个STC15W408AS,timer1死活打不开(用官网的测试程序也不行)&( 11:16)&排除你个人的问题可能就是中奖了。不会是你焊接温度过高,或者ESD因素破坏了相关电路吧?这个更夸张。T0,T1我经常用,目前未出问题,连16位重装都很好用。T3,T4之类就没试过。
UID:813565
在线时间2266小时
M币3721专家193
回 la45088d1 的帖子
:发发我的吧![图片]对了,STC是经过两级稳压,电压一直再4.97左右,极为稳定,AMS1117的功力可信。 ( 11:11) 你的用这方法是看不出问题所在的,如怀疑有问题,就用最小化的程序测试一下就知了,如你的板,就在AD0接一个2.5v的电压,采集后把采集值显示在数码管上,看看值是不是512左右(5V供电),然后再进行温度测试。我常用stc单片机的ad制作小制作,稳定性还是行的。
UID:1274537
在线时间656小时
M币619专家1
:[表情]详细看官方手册吧,这个型号的单片机没时钟1的,只有时钟0及2.[图片]&( 11:23)&多谢指点,真的是我想多了
1到第8) ? 8 :
location='read.php?tid=1989314&page='+page+'';}">页8) ? 8 :
location='read.php?tid=1989314&page='+page+'';">确认
访问内容超出本站范围,不能确定是否安全
“新手上路”发帖需审核后才能显示(请认真发帖),达到数码9级后取消此限制
您目前还是游客,请
&回复后跳转到最后一页
Code by , Time now is:06-06 14:51, Total 0.165049(s) query 13,
Gzip enabled&查看: 5595|回复: 0
关于单片机EEPROM数据保存的若干经验总结 附带stc单片机程序
&&因为要保存的数据可能是千变万化的,字长可能从8位到32位,其中包括char(8)、short int(16)、 int(32)、float(32),而不同数据类型在不同体系架构上字长各不相同,复杂点的甚至包括结构体Struct,
因为结构体包含数据大小未知,完成由用户定义,如果保存数据时要考虑到这么多的变化,那能把人都搞晕,因此设计一个以不变应万变的数据保存机制就很好了,好比是复杂平台中的数据串行化保存。
在单片机里面不可能实现这么高级的技术,但是也可以通过一个小小的技巧实现类似功能,方式就是通过联合体来保存,比如下面所示
& && &&&struct& && && &e2prom_data
& && &&&char TEM_
& && &&&unsigned int sterilization_temperature[10];//0.1
& && &&&unsigned char sterilization_time_min[10];
& && &&&unsigned char exhaust_
& && &&&unsigned char prebalance_time_
& && &&&};
union sector
& && &&&struct e2prom_data sterlization_
& && &&&unsigned char storage[ sizeof(struct e2prom_data) ];
& &联合sector代表实际的扇区,大小不能超过扇区大小,而上面的结构体就用来保存真正要用到的变量,然后通过联合体sector里面的unsigned char storage,统一转换成1个字节来保存实际数据,极其方便。
而要读取数据的时候可以通过下面的&&void read_sector(char secn)函数来统一操作,把数据统一读取到内存中,确认保存后再通过void write_sector(char secn)统一保存。
效率很高,用内存来缓存数据,可以减小EEPROM擦写次数,提高寿命。
void read_sector(char secn)
{
&&& & & &
& & & & int E2prom_sector_start_addr=(secn-1)*512;
& & & & for(i=0;i& sizeof(struct& & & & e2prom_data);i++)
& & & & {
& & & & e2prom.storage[i]=Byte_Read( i+ E2prom_sector_start_addr);
& & & & }
& & & && &IAP_Disable();
}
void write_sector(char secn)
{
& & & &
& & & &
& & & & int E2prom_sector_start_addr=(secn-1)*512;
& & & & Sector_Erase(E2prom_sector_start_addr);
& & & & for(i=0;i& sizeof( struct & & & & e2prom_data );i++)
& & & & {
& & & & Byte_Program(i + E2prom_sector_start_addr, e2prom.storage[i]);
& & & & }
& & & && &IAP_Disable();
}复制代码
唯一不足的地方是实际数据地址是固定的,如果常年累月读写次数多了的话,EEPROM还是有可能出问题的,下一步改进的地方就是通过实际一个虚拟存储空间来延长EEPROM寿命,
实际方案是比如一个扇区是1K字节,那么把1k分成256个单元,每个单元4个字节,扇区首单元保存扇区状态,剩余255个单元作为实际存储单元,而每个存储单元又分成2+2布局,前两字节保存实际数据,后两字节保存虚拟地址,1.写入时写入数据紧跟后面写入虚地址VirtAddVarTab(0&=i&NumbOfVar)
2.每个Page第一个地址写入该页状态(Earse,Reveice,Vild)
相同地址再次写入时不会把上次写的擦掉,而是在模拟EEPROM区尾部未写过的地方再次写入数据、虚地址,
3、 读的时候是从尾部开始匹配地址,也就是读取最后一次写的内容。
4、模拟EEPROM区分为2页,如果一页满了把这一页内地址不重复的数据复制到另一页后擦除,2页交替使用。
一个代码:
#include &reg52.h&& && && && && &&&//调用单片机头文件
#define uchar unsigned char&&//无符号字符型 宏定义& && &&&变量范围0~255
#define uint&&unsigned int& && && &//无符号整型 宏定义& && &&&变量范围0~65535
#include &intrins.h&
uchar a_a;
//数码管段选定义& && &0& &&&1& & 2& & 3& & 4& & 5& && &&&6& && && &7& && && & 8& && && &&&9& && &&&
uchar code smg_du[]={0x28,0xee,0x32,0xa2,0xe4,0xa1,0x21,0xea,0x20,0xa0,
& && && && && && && && && && && && && && & 0x60,0x25,0x39,0x26,0x31,0x71,0xff};& && && &//断码
uchar dis_smg[8]& &={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8};
//数码管位选定义
sbit smg_we1 = P3^4;& && && && &//数码管位选定义
sbit smg_we2 = P3^5;
sbit smg_we3 = P3^6;
sbit smg_we4 = P3^7;
sbit c_send& &= P3^2;& && && && && & //超声波发射
sbit c_recive = P3^3;& && && && && & //超声波接收
sbit beep = P2^3;& &//蜂鸣器IO口定义
uchar smg_i = 3;& & //显示数码管的个位数
bit flag_300
& && && && && & //距离
uint set_d;& && && && && && &&&//距离
uchar flag_csb_& & //超声波超出量程
uint&&flag_time0;& && & //用来保存定时器0的时候的
uchar menu_1;& && && &&&//菜单设计的变量
/***********************1ms延时函数*****************************/
void delay_1ms(uint q)
{
& && &&&uint i,j;
& && &&&for(i=0;i&q;i++)
& && && && && & for(j=0;j&120;j++);
}
/***********************处理距离函数****************************/
void smg_display()
{
& && &&&dis_smg[0] = smg_du[distance % 10];
& && &&&dis_smg[1] = smg_du[distance / 10 % 10];
& && &&&dis_smg[2] = smg_du[distance / 100 % 10] & 0 ;& && &&&
}
#define RdCommand 0x01 //定义ISP的操作命令
#define PrgCommand 0x02
#define EraseCommand 0x03
#define Error 1
#define Ok 0
#define WaitTime 0x01 //定义CPU的等待时间
sfr ISP_DATA=0xe2;&&//寄存器申明
sfr ISP_ADDRH=0xe3;
sfr ISP_ADDRL=0xe4;
sfr ISP_CMD=0xe5;
sfr ISP_TRIG=0xe6;
sfr ISP_CONTR=0xe7;
/* ================ 打开 ISP,IAP 功能 ================= */
void ISP_IAP_enable(void)
{
& && && &EA = 0;& && & /* 关中断& &*/
& && && &ISP_CONTR = ISP_CONTR & 0x18;& && & /*
*/
& && && &ISP_CONTR = ISP_CONTR | WaitT /* 写入硬件延时 */
& && && &ISP_CONTR = ISP_CONTR | 0x80;& && & /* ISPEN=1&&*/
}
/* =============== 关闭 ISP,IAP 功能 ================== */
void ISP_IAP_disable(void)
{
& && && &ISP_CONTR = ISP_CONTR & 0x7f; /* ISPEN = 0 */
& && && &ISP_TRIG = 0x00;
& && && &EA& &=& &1;& &/* 开中断 */
}
/* ================ 公用的触发代码 ==================== */
void ISPgoon(void)
{
& && && &ISP_IAP_enable();& &/* 打开 ISP,IAP 功能 */
& && && &ISP_TRIG = 0x46;&&/* 触发ISP_IAP命令字节1 */
& && && &ISP_TRIG = 0xb9;&&/* 触发ISP_IAP命令字节2 */
& && && &_nop_();
}
/* ==================== 字节读 ======================== */
unsigned char byte_read(unsigned int byte_addr)
{
& && &&&EA = 0;
& && && &ISP_ADDRH = (unsigned char)(byte_addr && 8);/* 地址赋值 */
& && && &ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);
& && && &ISP_CMD& &= ISP_CMD & 0xf8;& &/* 清除低3位&&*/
& && && &ISP_CMD& &= ISP_CMD | RdC /* 写入读命令 */
& && && &ISPgoon();& && & /* 触发执行&&*/
& && && &ISP_IAP_disable();& & /* 关闭ISP,IAP功能 */
& && && &EA&&= 1;
& && && &return (ISP_DATA);& & /* 返回读到的数据 */
}
/* ================== 扇区擦除 ======================== */
void SectorErase(unsigned int sector_addr)
{
& && && &unsigned int iSectorA
& && && &iSectorAddr = (sector_addr & 0xfe00); /* 取扇区地址 */
& && && &ISP_ADDRH = (unsigned char)(iSectorAddr && 8);
& && && &ISP_ADDRL = 0x00;
& && && &ISP_CMD = ISP_CMD & 0xf8;& &/* 清空低3位&&*/
& && && &ISP_CMD = ISP_CMD | EraseC /* 擦除命令3&&*/
& && && &ISPgoon();& && & /* 触发执行&&*/
& && && &ISP_IAP_disable();& & /* 关闭ISP,IAP功能 */
}
/* ==================== 字节写 ======================== */
void byte_write(unsigned int byte_addr, unsigned char original_data)
{
& && && &EA&&= 0;
//& && && &SectorErase(byte_addr);
& && && &ISP_ADDRH = (unsigned char)(byte_addr && 8);&&/* 取地址&&*/
& && && &ISP_ADDRL = (unsigned char)(byte_addr & 0x00ff);
& && && &ISP_CMD&&= ISP_CMD & 0xf8;& & /* 清低3位 */
& && && &ISP_CMD&&= ISP_CMD | PrgC&&/* 写命令2 */
& && && &ISP_DATA = original_& &/* 写入数据准备 */
& && && &ISPgoon();& && & /* 触发执行&&*/
& && && &ISP_IAP_disable();& &&&/* 关闭IAP功能 */
& && && &EA =1;
}
/******************把数据保存到单片机内部eeprom中******************/
void write_eeprom()
{
& && &&&SectorErase(0x2000);
& && &&&byte_write(0x2000, set_d % 256);
& && &&&byte_write(0x2001, set_d / 256);
& && &&&byte_write(0x2058, a_a);& && &&&
}
/******************把数据从单片机内部eeprom中读出来*****************/
void read_eeprom()
{
& && &&&set_d&&= byte_read(0x2001);
& && &&&set_d &&= 8;
& && &&&set_d&&|= byte_read(0x2000);
& && &&&a_a& && &= byte_read(0x2058);
}
/**************开机自检eeprom初始化*****************/
void init_eeprom()
{
& && &&&read_eeprom();& && && && && & //先读
& && &&&if(a_a != 1)& && && && && & //新的单片机初始单片机内问eeprom
& && &&&{
& && && && && & set_d = 50;
& && && && && & a_a = 1;
& && && && && & write_eeprom();& && && &&&//保存数据
& && &&&}& && &&&
}
/********************独立按键程序*****************/
uchar key_& && && &//按键值
void key()& && && &//独立按键程序
{
& && &&&static uchar key_
& && &&&key_can = 20;& && && && && && & //按键值还原
& && &&&P2 |= 0x07;
& && &&&if((P2 & 0x07) != 0x07)& && && && && & //按键按下
& && &&&{
& && && && && & delay_1ms(1);& && && && && && && &//按键消抖动
& && && && && & if(((P2 & 0x07) != 0x07) && (key_new == 1))
& && && && && & {& && && && && && && && && && && && && && && && &//确认是按键按下
& && && && && && && && &key_new = 0;
& && && && && && && && &switch(P2 & 0x07)
& && && && && && && && &{
& && && && && && && && && && &&&case 0x06: key_can = 3;& && && &&&//得到k2键值
& && && && && && && && && && &&&case 0x05: key_can = 2;& && && &&&//得到k3键值
& && && && && && && && && && &&&case 0x03: key_can = 1;& && && &&&//得到k4键值
& && && && && && && && &}
& && && && && & }& && && && && && && && &
& && &&&}
& && &&&else
& && && && && & key_new = 1;& && &&&
}
/****************按键处理显示函数***************/
void key_with()
{
& && &&&if(key_can == 1)& && && && && & //设置键
& && &&&{
& && && && && & menu_1 ++;
& && && && && & if(menu_1 &= 2)
& && && && && & {
& && && && && && && && &menu_1 = 0;
& && && && && && && && &smg_i = 3;& && && && && & //只显示3位数码管
& && && && && & }
& && && && && & if(menu_1 == 1)
& && && && && & {
& && && && && && && && &smg_i = 4;& && && &&&//只显示4位数码管
& && && && && & }
& && &&&}
& && &&&if(menu_1 == 1)& && && && && && && && &//设置报警
& && &&&{
& && && && && & if(key_can == 2)
& && && && && & {
& && && && && && && && &set_d ++ ;& && && && && & //加1
& && && && && && && && &if(set_d & 400)
& && && && && && && && && && &&&set_d = 400;
& && && && && & }
& && && && && & if(key_can == 3)
& && && && && & {
& && && && && && && && &set_d -- ;& && && && && & //减1
& && && && && && && && &if(set_d &= 1)
& && && && && && && && && && &&&set_d = 1;
& && && && && & }
& && && && && & dis_smg[0] = smg_du[set_d % 10];& && && && && && & //取小数显示
& && && && && & dis_smg[1] = smg_du[set_d / 10 % 10] ;& && && &//取个位显示
& && && && && & dis_smg[2] = smg_du[set_d / 100 % 10] & 0 //取十位显示
& && && && && & dis_smg[3] = 0x60;& && && && && & //a
& && && && && & write_eeprom();& && && && && && && && && &//保存数据
& && &&&}& && &&&
}&&
/****************报警函数***************/
void clock_h_l()
{
& && &&&
& && &&&if(distance &= set_d)
& && &&&{
& && && && && & value ++;&&//消除实际距离在设定距离左右变化时的干扰
& && && && && & if(value &= 2)
& && && && && & {
& && && && && && && && &beep = ~& && && &&&//蜂鸣器报警& && &&&
& && && && && & }
& && &&&}
& && &&&else
& && &&&{
& && && && && & value = 0;
& && && && && & beep = 1;& && && && && & //取消报警
& && &&&}& && &&&
}
/***********************数码位选函数*****************************/
void smg_we_switch(uchar i)
{
& && &&&switch(i)
& && &&&{
& && && && && & case 0: smg_we1 = 0;&&smg_we2 = 1; smg_we3 = 1;&&smg_we4 = 1;
& && && && && & case 1: smg_we1 = 1;&&smg_we2 = 0; smg_we3 = 1;&&smg_we4 = 1;
& && && && && & case 2: smg_we1 = 1;&&smg_we2 = 1; smg_we3 = 0;&&smg_we4 = 1;
& && && && && & case 3: smg_we1 = 1;&&smg_we2 = 1; smg_we3 = 1;&&smg_we4 = 0;
& && &&&}& && &&&
}
/***********************数码显示函数*****************************/
void display()
{
& && &&&& &
& && &&&i++;
& && &&&if(i &= smg_i)
& && && && && & i = 0;& && &&&
& && &&&smg_we_switch(i);& && && && && &&&//位选
& && &&&P1 = dis_smg&i&;& && && && && &&&//段选& && && && && &
/******************小延时函数*****************/
void delay()
{
& && &&&_nop_();& && && && && && && && && & //执行一条_nop_()指令就是1us
& && &&&_nop_();
& && &&&_nop_();
& && &&&_nop_();
& && &&&_nop_();
& && &&&_nop_();
& && &&&_nop_();
& && &&&_nop_();
& && &&&_nop_();&&
& && &&&_nop_();
/*********************超声波测距程序*****************************/
void send_wave()
{
& && &&&c_send = 1;& && && && && && && && && &//10us的高电平触发
& && &&&delay();
& && &&&c_send = 0;& && && &
& && &&&TH0 = 0;& && && && && && && && &&&//给定时器0清零
& && &&&TL0 = 0;
& && &&&TR0 = 0;& && && && && && && && && && && & //关定时器0定时
& && &&&while(!c_recive);& && && && && && &//当c_recive为零时等待
& && &&&TR0=1;
& && &&&while(c_recive)& && && && && && && & //当c_recive为1计数并等待
& && &&&{
& && && && && & flag_time0 = TH0 * 256 + TL0;
& && && && && & if((flag_time0 & 40000))& && &//当超声波超过测量范围时,显示3个888
& && && && && & {
& && && && && && && && &TR0 = 0;
& && && && && && && && &flag_csb_juli = 2;
& && && && && && && && &distance = 888;
& && && && && && && && && && && && && &
& && && && && & }
& && && && && & else
& && && && && & {
& && && && && && && && &flag_csb_juli = 1;& && &&&
& && && && && & }
& && &&&}
& && &&&if(flag_csb_juli == 1)
& && &&&{& && &&&
& && && && && & TR0=0;& && && && && && && && && && && && && && && && && && && &//关定时器0定时
& && && && && & distance =flag_time0;& && && && && && && && & //读出定时器0的时间
& && && && && & distance *= 0.017;& && && && && &// 0.017 = 340M / 2 = 170M = 0.017M 算出来是米
& && && && && & if((distance & 500))& && && && && && && && && && && &//距离 = 速度 * 时间
& && && && && & {& && &&&
& && && && && && && && &distance = 888;& && && && && && && && && && && &//如果大于3.8m就超出超声波的量程
& && && && && & }
& && &&&}&&
}
/*********************定时器0、定时器1初始化******************/
void time_init()& && && &
{
& && &&&EA&&= 1;& && && && && && & //开总中断
& && &&&TMOD = 0X11;& && && & //定时器0、定时器1工作方式1
& && &&&ET0 = 0;& && && && && && &//关定时器0中断
& && &&&TR0 = 1;& && && && && && &//允许定时器0定时
& && &&&ET1 = 1;& && && && && && &//开定时器1中断
& && &&&TR1 = 1;& && && && && && &//允许定时器1定时& && &&&
}
/***************主函数*****************/
void main()
{
& && &&&beep = 0;& && && && && &&&//开机叫一声& &
& && &&&delay_1ms(150);
& && &&&P0 = P1 = P2 = P3 = 0& && && &&&//初始化单片机IO口为高电平
& && &&&send_wave();& && &&&//测距离函数
& && &&&smg_display();& && &&&//处理距离显示函数
& && &&&time_init();& && &&&//定时器初始化程序
& && &&&init_eeprom();&&//开始初始化保存的数据
& && &&&send_wave();& && &&&//测距离函数
& && &&&send_wave();& && &&&//测距离函数
& && &&&while(1)
& && &&&{& && && && && && &
& && && && && & if(flag_300ms == 1)
& && && && && & {& && && && && &
& && && && && && && && &flag_300ms = 0;
& && && && && && && && &clock_h_l();& & //报警函数
& && && && && && && && &if(beep == 1)
& && && && && && && && && && &&&send_wave();& && &&&//测距离函数
& && && && && && && && &if(menu_1 == 0)
& && && && && && && && && && &&&smg_display();& && && &//处理距离显示函数
& && && && && & }
& && && && && & key();& && && && && && && && && && && && && &&&//按键函数
& && && && && & if(key_can & 10)
& && && && && & {
& && && && && && && && &key_with();& && && && && && && && & //按键处理函数
& && && && && & }
& && &&&}
}
/*********************定时器1中断服务程序************************/
void time1_int() interrupt 3
{& && &&&
& && &&&& && && && && && && && & //定时2ms中断一次
& && &&&TH1 = 0xf8;
& && &&&TL1 = 0x30;& &&&//2ms
& && &&&display();& && && && && & //数码管显示函数
& && &&&value++;
& && &&&if(value &= 150)
& && &&&{
& && && && && & value = 0;
& && && && && & flag_300ms = 1;
& && &&&}
}
Powered by

我要回帖

更多关于 单片机接收串口数据 的文章

 

随机推荐