




版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领
文档简介
从单片机初学者迈向单片机工程师:一 周第一章----写 二 周第二章----学会 三 四 五 六 第一章——按键程序编写的基 七 八 综合应用之一——如何设计复杂的多任务程 九 综合应用之二——DS1320/DS18B20应 一、LED周第一章-----写需要的学习资料。但是,随着学习的深入,会慢慢发现,网络提供的东西是有限度的,好像大部且也只是仅仅作功能性的演示。于是有些人选择了放弃,或者是转移到其他上面去了,而部分人选择了继续摸索下去,结合市面上的书籍,然后在网络上锲而不舍的搜料,再从牛人的只言片语中了之后也不会在网络上轻易自己的学习成果。如此恶性循环下去,也就不难理解为什么初级的学习资悲,的点周最大了这样的一个名字“从片机初学者向单片机程师”。名字大挺响亮,给力大后给@@.二、LED周第二章-----学会在以后的系列文章中,以51内核的单片机为载体,C语言为编程语言,开发环境为KEILuv3。至于够满足系统的需求。在学习掌握C语言的同时,也还需要利用闲余的时间去学习了解汇编语言。void{LedInit();{LED=ONLED=OFF;}}果就是LED以1HZ的频率进行闪烁。下面让分析上面的程序有没有什么问题。看来看出,好像很正常的啊,能有什么问题呢?这个时候应该换一个思路去想了。试想,整个程序除了LEDONLED=OFF余的时间,全消耗在了DelayMs(500)这两个函数有哪些任务需要执行,也不要让它停留在某个地方空转消耗CPU时间。下面让从另外一个角度来考虑如何点亮一颗LED。 示一般的LED10~20mA而低电流LED的工作电流在2mA以下(亮度与普通发光管相同。在上图中可知,当Q1~Q8引脚上面的电平为低电平时,LED发光。通过LED的电流约(VCC-Vd)/RA2。其中Vd为LED导通后的压降,约为1.7V左右。这个导通压降根据LED颜色的不红色的压降为1.82-1.88V,电流5-8mA,橙色的压降为1.7-1.8V,电流3-5mA白色的压降为3-3.2V10-15mA,(供电电压5V,LED直径为5mm)通过这个真值表可以看出。当OutputEnable引脚接低电平的时候,并且LatchEnable引脚为高电平的时候,Q端电平与D端电平相同。结合的LED硬件连接图可以知道LED_CS端为高电平时候,P0口电平的变化即Q端的电平的变化,进而引起LED的亮灭变化。由于单片机的驱动能力有限,在此,否则可能会烧坏74HC573这个。为35mA整个允许通过的最大电流为75mA。在设计相应的驱动电路时候,这些参数是相当重要脚允许通过的电流35mA,你就设计35mA,这个时候你应该把设计的上限值定20mA左右才能保首先定义LED的接口#defineLED电平时,LED熄灭。#define LED= //所有LED#define LED= //所有LED熄下面到了重点了,究竟该如何CPU,避免其做延时空等待这样的事情呢。很简单,为系统产当这个计数值达到500时候,清零该计数值,同时把LED的状态改变。unsignedintg_u16LedTimeCount0 //LED计数unsignedcharg_u8LedState0 //LED状态标志0表示亮,1表示熄void{if(0g_u8LedState)//如果LED的状态为亮,则点亮{} //否则熄灭{}}void{ {g_bSystemTime1Ms=0;g_u16LedTimeCount++; //LED计数器加一if(g_u16LedTimeCount500计数500,500MS到了,改变LED{g_u16LedTimeCount=0;g_u8LedState=!g_u8LedState;}}}上面有一个变量没有提到,就是g_bSystemTime1Ms。这个变量可以定义为位变量或者是其它变量,在的定时器中断函数中对其置位,其它函数使用该变量后,应该对其复位(清0)。voidmain(void){{LedProcess();}}因为LED的亮或者灭依赖于LED状态变量(g_u8LedState)的改变,而状态变量的改变,又依赖LED计数器的计数值(g_u16LedTimeCount,只有计数值达到一定后,状态变量才改变)所以,两个函数都没有堵塞CPU的地方。让来从头到尾分析一遍整个程序的流程。程序首先执行LedProcess函0以便下一个时标消息的到来LED计数器加一,然后再LED计数器是否到达预先想要的值500,如果没有,则退出函数,如果有,对计数器清0,以便下次重新计数,同时把LED状态变量取反,然后退出函数。状态来决定是否点亮LED。这些函数执行所花的时间都是相当短的,如果主程序中还有其它函数,则以及整个的驱动能力sbitLED_SEG=P1^4数码管段选sbitLED_DIG=P1^5数码管位选sbitLED_CS11P1^6;//led控制位sbitir=P1^7;#defineLED bitg_bSystemTime1Ms0 unsignedintg_u16LedTimeCount0LED计数unsignedcharg_u8LedState0 //LED状态标志0表示亮,1表示熄#define LED= //所有LED#define LED= void{TMOD&=0xf0TMOD|=0x01; //定时器0工作方式1TH0=0xfc; TL0=0x66;TR0=1;ET0=1;}void{if(0g_u8LedState)//如果LED的状态为亮,则点亮{} //否则熄灭{}}void{ //系统1mS时标{g_bSystemTime1Ms=0;g_u16LedTimeCount //LED计数器加一if(g_u16LedTimeCount500)//计数达500,500mS到了,改变LED{g_u16LedTimeCount=0;g_u8LedState=!g_u8LedState }}}void{EA=1;LED_CS11174HC595LED_SEG=0;//数码管段选和位选(因为它们和LED共用P0口)LED_DIG=0;{LedProcess();}}{TH0= 0xfc; TL0=0x66; }点熄 通过上一章的学习,你已经掌握了如何在程序中CPU了。希望能够1000培训。由于学校来参加国赛和省赛,因此积累了一定数量的驱动模块,那些日子,老师每天都会布置一定量的任务,让用这些模块组合起来,完成一定用模块化编程的方式去编写。很长一段时间以来,一直有单片机者在上也可以看出模块化编程的一个好处,就是可重复利用率高。下面让揭开模块 不管模块的实现细节。好比 些过程对用户而言,就是是一个黑盒子。模块的接口,这个时候关心的是,它的模块实现了什么样的接口,我该如何去调用,至于模块是如何组织的,对于我而言,无需过多关注。而追求接口 假设有一个LCD.C文件,其提供最基本的LCD的驱动函LcdPutChar(charcNewValue);//在当前位置输出一个字符而在的另外一个文件中需要调用此函数,那么该如何做呢?因而为了让外部函数或者文件调用提供的接口功能就必须包含提供的 #define LcdPutChar(charcNewValue);extern 需要调用LcdPutChar(charcNewValue)由于没有定义过_LCD_H_因此#ifndef_LCD_H_条件成立,于是定义含时候,已经将_LCD_H_定义过了。因此#ifndef_LCD_H_不成立,整个头文件内容就没有被包含。假设没有这样的条件编译语句,那么两个文件都包含了externLcdPutChar(charcNewValue);就会引起重复包含的错误。不得不说的很多朋友似乎了程序中利用如下语句来对数据类型进行定#defineuintunsigned#defineucharunsigneduintg_nTimeCounter=0#definePINTunsignedint*//定义unsignedintPINTg_npTimeCounter,g_npTimeState庆幸的是C语言已经为考虑到了这一点。typedef正是为此而生。为了typedefunsignedintuint16;//给指向无符号整形变量起一个别名uint16typedefunsignedint*puint16;/puint16uint16g_nTimeCounter=0;//定义一个无符号的整形变量puint16g_npTimeCounter;在使用51单片机的C语言编程的时候,整形变量的范围是16位,而在基于32的微处理下的整形变量是32位。倘若在8位单片机下编写的一些代码想要移植到32位的处理器上,那么很可能就需要在源文件中到处修改变量如在8位单片机的平台下,有如下一个变量定 g_nTimeCounter=0可以直接修改uint16的定义,即typedefunsignedshort uint16文件名 在上一章中主要完成的功能是P0口所驱动的LED以1Hz的频率闪烁。其中用到了定时器,以及LED驱动模块。因而可以简单的将整个工程分成三个模块,定时器模块,LED模块,以及主函数Timer.hTimer.c-- 下面的内容就主要以为主了。同时辅以少量文字说明。 AT89S52为例。就可以直接保存到src文件 #includebitg_bSystemTime1Ms0 void{TMOD&=0xf0TMOD|=0x01; //定时器0工作方式1TH0= 0xfc; TL0=0x66;TR0=1;ET0=1;}{TH0=0xfc; TL0=0x66; }由于在Led.c文件中需要调用的g_bSystemTime1Ms变量。同时主函数需要调用Timer0Init()初始化函数,所以应该对这个变量和函数在头文件里作外部。以方便其它Timer.h内容如下。#ifndef_TIMER_H_#define_TIMER_H_Led.c#include#include#include#includestaticuint16g_u16LedTimeCount0LEDstaticuint8g_u8LedState0 #defineLED #define LED #define LED void{)//{} {}}void{ {g_bSystemTime1Ms=0;g_u16LedTimeCount++; {g_u16LedTimeCount=0;g_u8LedState=!g_u8LedState }}}Led.h内容:#ifndef_LED_H_externvoidLedProcess(void)#include#include#include#includesbitLED_SEG=P1^4;//数码管段选sbitLED_DIG=P1^5数码管位选sbitLED_CS11=P1^6;//led控制位void{LED_SEG=0;//数码管段选和位选(因为它们和LED共用P0口)LED_DIG=0;Timer0Init();EA=1;{LedProcess();}}typedef 的控制方式分类的,除了型,还有PFM型和、PFM混合型。脉宽调制式开关型稳压电路是在读起来有点晦涩难懂。其实简单的说来,技术就是通过调整一个周期固定的的占空比,来调节输出电压的平均当电压,电流或者功率等被控量。可以用一个水龙头来类比,把1S时间分成50开肯定要小的多。同样的道理,可以通过控制20mS时间里水阀开启的时间的长短来控制流过的水的多少。那么在1S内平均流出的水流量也就可以被控制了。当调整的占空比时,就会引起电压或者电流的改变,LED的明暗状态就会随之发生相应的变化,大家都知道人眼有一个临界频率,当LED的闪烁频率达到一定的时候,人眼就分辨不出LED是否在闪烁了。就像平常看电视一样,看起来画面是连续的,实质不是这个样子,所有连续动作都是一帧帧分).即最亮的时候其灰度等级为99,为0的时候最暗,也就是熄灭了。于是乎定义的占空比上限为99,下限定义为0#defineLED__LIMIT_MAX #defineLED_ 假定LED的闪烁频率为50HZ,而亮度变化的范围为0~99共100等分。则每一等分所占用的时间为1/(50*100)=200us即在改变LED的亮灭状态时,应该是在200us整数倍时刻时。在这里我的时间内LED可以从暗逐渐变亮,在下一个2S内可以从亮逐渐变暗,然后不断循环。由于大部分的内容都可以在中断中完成,因此,的大部分代码都在Timer.c这个文件中编写,主函数#include#include#defineLED #define LED= //所有LED#define LED //所有LED#defineLED__LIMIT_MAX #defineLED_ staticuint8s_u8TimeCounter0staticuint8s_u8LedDirection0LED方向控制0:渐亮1:渐staticint8s_s8LedCounter=0;//LED占空void{TMOD&=0xf0TMOD|0x01 //0工作方式TH0= 0xff; TL0=0x47;TR0=1;ET0=1}{staticint8s_s8Counter=0TH0=0xff; TL0=0x47;{s_u8TimeCounter=0if((s_s8LedCounter<=LED__LIMIT_MAX)&&(0=={s_s8LedCounter++{s_u8LedDirection=1s_s8LedCounter=LED__LIMIT_MAX}}if((s_s8LedCounter>=LED__LIMIT_MIN)&&(1=={{s_u8LedDirection=0s_s8LedCounter=LED__LIMIT_MIN}}s_s8Counter=s_s8LedCounter;//获取LED的占空}if(s_s8Counter>0)//占空比大于0,则点亮LED,否则熄灭{}{}}其实技术在实际生活中应用的非常多。比较典型的应用就是控制电机的转速,控制充电电流的大小,等等。而随着技术的发展,也出现了其他类型的技术,如相电压,线电压,S LED程序并不是那么的简单。曾经有人这样,如果用数码管和按键,做一个简易的可60%了。此话我深信不疑。我遇到过很多要求:系统有四个按键,功能分别是调整,加,减,确定。在按下调整键时候,显示时的1Hz频率闪烁。如果再次按下调整键,则分开闪烁,依次循环,直到按下确{{delayms(2);}}的程序在实际中是根本就无法用的,更何况,它这里也调用了delayms(2)这个函数来延时2ms这更是令深恶痛绝本章的内容正是探讨如何解决多任务环境下(OS)的数码管程序设计的编写问题。级联,留给单片机的接口只需要时钟线,数据线,因此比较节省I/O口。如下图所示:由上图可以看出。874HC573驱动。同时每一个数码管的公设数码管的扫描频率为50Hz,则完成一轮扫描的时间就是1/50=20ms。的系统共82082.5ms。假设程序中所有任务如下:{LedDisplay(); rocess(); //AD处理TimerProcess();//时间相关处理DataProcess();//数据处理}LedDisplay()这个任务的执行时间,如同刚才计算的那样,50Hz频率扫描,则该函数imerProcess1ms,DataProcess()10ms主函数执行一遍的总时间为20211033msLedDisplay()这个函数的扫描频50Hz了,而是1/3330.3Hz。这个频率数码管已经可以感觉到闪烁了,因此不符合的要求。为什么会出现这种情况呢?刚才计算的50Hz是系统只有2.5ms的时标消息。LedDisplay(),每次接收到这个消息的时候,扫描一位数码管。这样8个时标消息过后,所有的数码管就都被扫描一遍了。可能有朋友会有这样的疑问:rocess()以及DataProcess()等函数执行的时间还是需要十几ms啊,在这十几ms2.5ms的时标消息了,这样岂不是漏掉了扫描,显示对于rocess(),TimerProcess(),DataProcess(),等任务依旧要采取此方法对CPU进行,使其执行的时间尽可能短暂,关于如何做到这一点,在以后的讲解如何设计多任#include<reg52.h>同时一个位变量,作为2ms时标消息的标志bitg_bSystemTime2Ms=0; 初始化定时器0void{TMOD&=0xf0TMOD|=0x01; //定时器0工作方式1TH0=0xf8; TL0=0xcc;TR0=1;ET0=1;}voidTime0Isr(void)interrupt{TH0 0xf8 TL0=0xcc }然后开始编写数码管的动态扫描函数。新建一个C源文件,并包含相应的头文件。#include<reg52.h>#include"Timer.h"codeuint8{}sbitio_led_seg_cs=P1^4;sbitio_led_bit_cs=P1^5;{ =datio_led_seg_cs=1; io_led_seg_cs=0;}{uint8temptemp=(0x01<<dat);//根据要选通的位计算出位码 =temp;io_led_bit_cs=1; io_led_bit_cs=0;}{staticuint8s_LedDisPos=0;{g_bSystemTime2Ms=0); if(pBuffer[s_LedDisPos] {}{}{s_LedDisPos=0}}}函数定义一个静态的变量s_LedDisPos,用来表示扫描数码管的位置。每当执行该函数一次的时候,s_LedDisPos的值会自加1,表示下次扫描下一个数码管。然后判断g_bSystemTime2Ms时标消息是否到了。如果到了,就开始执行相关扫描,否则就直接跳出函数SendLedBitData(8);的作用是消隐因为的系统的段选和位选是共用P0口的。应数码管的点亮,尽管这个时间很短暂。但是因为的数码管是不断扫描的,所以看起来if(pBuffer[s_LedDisPos]=='-') 家可以看到在定义数码管的段码表的时候,我多加了一个字节的代码0xbf:codeuint8{}]]);{s_LedDisPos=0}然后s_LedDisPos自加1,以便下次执行本函数时,扫描下一个数码管。因为的系统8s_LedDisPos70。否则,没有任何一个数SendLedBitData(8); 102030#include"Timer.h"sbitio_led=P1^6;void{io_led=0 //发光二极管与数码管共用P0口,这里掉发光二极管的锁存输Timer0Init();g_u8LedDisplayBuffer[0]=1;g_u8LedDisplayBuffer[1]=0;g_u8LedDisplayBuffer[2]='-';g_u8LedDisplayBuffer[3]=2;g_u8LedDisplayBuffer[4]=0;g_u8LedDisplayBuffer[5]='-';g_u8LedDisplayBuffer[6]=3;g_u8LedDisplayBuffer[7]=0;EA=1;{}}知道,之前以及设置了一个扫描数码管用到的2ms时标。如果再对这个时间。再根据这个1S的时间更新显示缓冲区即可。听起来很简单,让实现它吧。首先在Timer.c中如下两个变量:bitg_bTime1S0 staticuint16s_u16ClockTickCount0;//2ms{s_u16ClockTickCount=0;g_bTime1S=1;}void{{g_bTime1S=0;if(++g_u8LedDisplayBuffer[7]==10){{g_u8LedDisplayBuffer[6]=0;{ =0;if(++g_u8LedDisplayBuffer[3]==6){ {{g_u8LedDisplayBuffer[1]=0;}}{{g_u8LedDisplayBuffer[1]=0;}}}}}}}}1001….诸如此类,我就不一一详述了。{g_u8LedDisplayBuffer[0]=nHour/10;g_u8LedDisplayBuffer[1]=nHour%10;g_u8LedDisplayBuffer[2]='-';g_u8LedDisplayBuffer[3]=nMinute/10;g_u8LedDisplayBuffer[4]=nMinute%10;g_u8LedDisplayBuffer[5]='-';g_u8LedDisplayBuffer[6]=nSecond/10;g_u8LedDisplayBuffer[7]=nSecond%10;}void{io_led=0 Timer0Init()EA=1{}}输入是必不可少的一部分。输入可以分很多种情况,譬的系统支持PS2键盘的接口,有的系统输入是基于编,有的系统输入是基于串口或者USB或者其它输入通道等等。总共有四个引脚,一般情况下,处于同一边的两个引脚是连接在一起的,如何分辨位检测一下即可。搞清楚这点非常重要,对于画PCB的时候的封装很有益。在程序中该I/O的电平的时候,其值为1(高电平);当按键S按下的时候,该被短接到GND,在程序中该I/O的电平的时候,其值为0(低电平)。这样,按键的按下与否,就和与该按键相连的I/O的电平的变化相对应起来。结论:在程序中通过检测到而将某个I/O的状态不断取反,这并不是想要的效果,假如该I/O控制着系统中某个重 If(0 { If(0 { }{return } }Delayms(20),20ms的时间,啥也没干,考虑我在等待按键,结果CPU就一直死死的盯住该按键,其它事情都不管了,那其它事情不干的返回值可以获取到如下的信息:按键按下(短按),按键长按,按键连发,按键。CALL机(CALL的那种,有 S1,在这个状态下,检测按键是否按下,如果有按下,则进入S1,如果有则可以返S4,在长按状态下每次进入按键程序时候对按键时间计数,当S5。如果按键键值为空键,则返回按键状态S6,否则继续停留在本状态。在按键连发状态下,如果按P3^0P3^3I/O因为51单片机I/O口结构的限制,在外部引脚状态的时候,需要向端口写1。在51单片机复位后,不需要进行此操作也可以进行外部引脚的操作。因此,在按键的端voidKeyInit(void){io_key_1=1;io_key_2=1;io_key_3=1;io_key_4=1} staticuint8{if(io_key_1==0)returnKEY_VALUE_1;if(io_key_2==0)returnKEY_VALUE_2;if(io_key_3==0)returnKEY_VALUE_3;if(io_key_4==0)returnKEY_VALUE_4;returnKEY_NULL;}sbitio_key_1=P3^0;sbitio_key_2=P3^1;sbitio_key_3=P3^2;sbitio_key_4=P3^3KeyScan()作为底层按键的驱动程序,为上层按键扫描提供一个接口,这样编写的上层#define #defineKEY_DOWN #defineKEY_LONG #defineKEY_CONTINUE #defineKEY_UP {staticuint8s_u8KeyState=KEY_STATE_INIT;staticuint8s_u8KeyTimeCount=0;staticuint8s_u8LastKey=KEY_NULL;//保存按键时候的键uint8KeyTemp=KEY_NULLKeyTemp=KeyScan(); {{{}}break {}break{{KeyTemp|KEY_DOWN;//按键按下s_u8KeyStateKEY_STATE_LONG}{}}break{{{KeyTemp|KEY_LONG;//长按键事件发生s_u8KeyState=KEY_STATE_CONTINUE;}}{}}break{{{s_u8KeyTimeCount=0;}}{}}break{}break
s_u8LastKey|=KEY_UP;KeyTemp=s_u8LastKey;default:break}}多键按下,功能键等等,亦相当简单,在下一章,就去实现它。void{uint8temp=0;LED_CS111流水灯输出允许LED_SEG=0;LED_DIG=0Timer0Init();KeyInit();EA=1;{Timer0MainLoop();if(KeyValue==(KEY_VALUE_1|KEY_DOWN))P0=~1;if(KeyValue==(KEY_VALUE_1|KEY_LONG))P0=~2;if(KeyValue==(KEY_VALUE_1|KEY_CONTINUE)){P0^=0xf0;}}}LED灯亮,等待2S后第二个LED亮,第一个熄灭,表示长按事件发生500ms灭亮灭亮亮灭亮灭,这也正是P0=0xa5这条语句的功能externunsignedcharkeyboard_self();externunsignedcharkeyboard_matrix();externunsignedcharkeyboard_self(){unsignedchartemp=0;//用于P2线上按键值staticunsignedchartemp_code=0;//保存按键值staticunsignedcharkey_flag=0;//按键有效标识{{}}{{{case0xB0:num_key=3;}}}}externunsignedcharkeyboard_matrix(){unsignedcharnum_key=0;//按键号unsignedchartemp=0;//P2口线数据{{}}{{{//P2^0case0xBE:num_key=3;//P2^1case0xBD:num_key=7;//P2^2case0xEB:num_key=9;case0x7B://P2^3case0xB7:num_key=15;}}{}}}如当按下P2.0线上的某个键时,程序将扫描到这个键,而后扫描线不变化, 首先来理解“任务”,所谓任务,就是需要CPU周期“关照”的事件,绝大多数任务不需要CPU一直“关照”,例如启动ADC的启动。甚至有些任务“害怕”CPU一直CPU做简单任务一定很浪费,事实也是如此,绝大多数简单任务,CPU都是在“空转(循环踏步延时)CPU不断“关照,其实这种“不断”也是有极限的,比如LCD10Hz就可以了,等等。看来,绝大多数任务都是工作在低速频度。而的CPU一旦运行起来,速度又很快,CPU的CPU分成多个慢的CPU,然后给不同的任务分配不同速度的CPU,这种设想是不是很好呢!确实很好,下面就看如何将“快”的CPU划分成多个“慢”的CPU。根据这种想法,需要合理分配CPU资源来“关照”不同的任务,最好能够根据任务CPU3所示的流程图,各个任务流程独立,各任务通过全,定的任务,事实上,任务切换就是这样实现的。44A所示,CPUCPU周期性唤回,根据任务设CPU资源,CPU为不同任务“关照”完成后,CPU,CPU关照的频度,选择最快的那个频度来设定定时器中断的节拍,一般选择200Hz,或者100Hz都可以。40HzC=5即可。在程序设计中,C代表着任务运行的节拍控制参数,用delay来描述,不同的任务用task0,{if(task_delay[0]==0)task0();//task0if(task_delay[1]==0)task1();//task1}切换本身就是一个Idle任务。{}#defineTIME_PER_SEC200 #defineCLOCK22118400定义时钟晶振,单位Hz#defineMAX_TASK externvoidtask0(void);//任务externvoidtask1(void);externvoidtask2(void);externvoidsbitf1Hz=P1^0;//端口定义sbitf5Hz=P1^1;sbitf10Hz=P1^2;sbitf20Hz=unsignedchartask_delay[4];//void{unsignedcharTMODTMOD&0XF0)| TH0=255-CLOCK/TIME_PER_SEC/12/256;TR0=1;ET0 }OS{unsignedcharTH0=255-CLOCK/TIME_PER_SEC/12/256;}/*main主函数*/voidmain(void){{//要产生1hz信号,翻转周期就是2Hz,以下同if(task_delay[1]==0){task1task_delay[1]TIME_PER_SEC/10;}//要产生5hz信号,翻转周期就是10Hz,以下同if(task_delay[2]==0){task2task_delay[2]TIME_PER_SEC/20;}{}}void{f1Hz=}void{f5Hz=}void{f10Hz=}void{f20Hz=}5CPU运行情况如图6所示,黑域表示CPU进程,系统启动后,CPU将无休止的CPUCPUus级的单片机,1ms可以执行上千条指令,对于像数码管扫描,键盘扫描,LCDCPU“关照”它们的时间并不长,关键是等待结果要很长时间。解决的办法就CPUCPU去关照其它任务。C语言实现,无硬件依赖性,需要单片机的资4个文件。Easy51RTOS.Uv2Keil工程文件,KEIL用户很熟悉的main.cmain函数和用户任务task函数文件 Easy51RTOS相关函数文件 #defineTIME_PER_SEC200 #defineCLOCK22118400定义时钟晶振,单位Hz#defineMAX_TASK externvoidtask0(void);externvoidtask1(void);externvoidtask2(void);externvoidtask3(void);externunsignedchartask_delay[MAX_TASK];externvoidrun(void(*ptask)());externvoid];//void{unsignedchari;for(i=0;i<MAX_TASK;i++)TMODTMOD&0XF0)| TH0=255-TL0=255-CLOCK/TIME_PER_SEC/12%256;TR0=1;ET0 }//OS{unsignedcharTH0=255-CLOCK/TIME_PER_SEC/12/256;}{}#defineTASK_DELAY0TIME_PER_SEC/1 //任务执行频度为1Hz#defineTASK_DELAY1TIME_PER_SEC/2 //任务执行频度为2Hz#defineTASK_DELAY2TIME_PER_SEC/10 #defineTASK_DELAY3TIME_PER_SEC/20 //任务执行频度为20Hzvoid(*codetask[])()={task0,task1,task2,task3};//获得任务PC指针sbitLED0P1^0;//LEDsbitLED1=P1^1;sbitLED2=P1^2;sbitLED3=/*main主函数*/voidmain(void){unsignedcharos_timer0_init();//节拍发生器定时器初始化EA=1; {({;}//}//}voidtask0(void)//{LED0=task_delay[0]=}voidtask1(void)//{LED1=task_delay[1]=}voidtask2(void)//{LED2=task_delay[2]=}voidtask3(void)//{staticunsignedcharstate=0;//定义静态局部变量switch(state){caseLED3=state=caseLED3=state=caseLED3=state=state=}}8({;}//task0具有最高优先级,task1、task2、task3优先级依次降voidtask3(void)switch(state)状态机实现了任务分段,这也是任务内系统延时的法。51单片机开发板来说。ds1302ds18b20应该是比较常见的两种。ds1302是具有SPI总线接口的时钟。ds18b20则是具有单总线接口的数字温 这是DS1302的31个RAM寄存器。在某些应用场合可以应用到。如想要做31RAM寄存器中的任意几个。当由于对于这些器件的操作基本上按照上面提供的时序图和相关命令字来进行操83.6V的可充电的电池。当系统正常工作时可以对电池进行涓流充电。当系统掉电时,DS1302由这个电池提供的能量继续sbitio_DS1302_RST=P2^0;sbitio_DS1302_IO =P2^1;sbitio_DS1302_SCLK=P2^2; #define #defineDS1302_MINUTE_WRITE #defineDS1302_HOUR_WRITE 0x84#defineDS1302_WEEK_WRITE #defineDS1302_DAY_WRITE #defineDS1302_MONTH_WRITE #defineDS1302_YEAR_WRITE #defineDS1302_MINUTE_READ #defineDS1302_HOUR_READ 0x85#defineDS1302_WEEK_READ #defineDS1302_DAY_READ #defineDS1302_MONTH_READ #defineDS1302_YEAR_READ #defineDS1302_SCLK_HIGH io_DS1302_SCLK=1; io_DS1302_SCLK=0;#defineDS1302_IO_HIGH io_DS1302_IO=1;#defineDS1302_IO_LOW io_DS1302_IO=0;#defineDS1302_IO_READio_DS1302_IO#defineDS1302_RST_HIGH io_DS1302_RST=1;#defineDS1302_RST_LOW io_DS1302_RST=0; {uint8Second;uint8Minute;uint8Hour;uint8Day;uint8Week;uint8Month;uint8Year; 要写的字 {uint8ifor(i=8;i>0;i--{if(Content&0x01{}{}Content>>=1}} Description:从DS1302当前设定的地址一个字节的内容 staticuint8v_DS1302Read_f(void){uint8i,ReadValue;for(i=8;i>0;i--{{}{}}} voidv_DS1302WriteByte_f(uint8Address,uint8Content Description:从DS1302指定的地址写入一个字节的内 Parameter: voidv_DS1302WriteByte_f(uint8Address,uint8Content){v_DS1302Write_f(Address);} uint8v_DS1302ReadByte_f(uint8Address){uint8ReadValue;v_DS1302Write_f(Address);} voidv_ClockInit_f(void ) voidv_ClockInit_f(void){if(v_DS1302ReadByte_f(0xc1)!=0xf0{v_DS1302WriteByte_f(0x8e,0x00); v_DS1302WriteByte_f(DS1302_YEAR_WRITE,0x08); v_DS1302WriteByte_f(DS1302_WEEK_WRITE,0x04); v_DS1302WriteByte_f(DS1302_MONTH_WRITE,0x12); //月v_DS1302WriteByte_f(DS1302_DAY_WRITE,0x11); v_DS1302WriteByte_f(DS1302_HOUR_WRITE,0x13); v_DS1302WriteByte_f(DS1302_MINUTE_WRITE,0x06); v_DS1302WriteByte_f(DS1302_SECOND_WRITE,0x40); //秒v_DS1302WriteByte_f(0x90,0xa5); v_DS1302WriteByte_f(0xc0,0xf0); v_DS1302WriteByte_f(0x8e,0x80); }} voidv_ClockUpdata_f(void){CurrentTime.Second=v_DS1302ReadByte_f(DS1302_SECOND_READ);CurrentTime.Minute=v_DS1302ReadByte_f(DS1302_MINUTE_READ);CurrentTime.Hour=v_DS1302ReadByte_f(DS1302_HOUR_READ); =v_DS1302ReadByte_f(DS1302_DAY_READ);CurrentTime.Month=v_DS1302ReadByte_f(DS1302_MONTH_READ);CurrentTime.Week=v_DS1302ReadByte_f(DS1302_WEEK_READ);CurrentTime.Year=v_DS1302ReadByte_f(DS1302_YEAR_READ);}DS18B20是单总线的数字温度传感器。其与单片机的接口只需要一根数据线即可。当然连片的唯一序列号。在出场的时候就已经设置好,用户无8位是以56CRC第二个和第三个字节分别存放高温和低温告警值。(RAMEEPROM中)第节为配置寄存器。第5~7个字节保留。第9个字节为前8个字节的CRC码。在对DS18B20进行读写编程时,必须严格保证读写的时序。否则将无法测温结果。DS18B20DS18B203个步骤:每一次读这样才能对DS18B20进行预定的操作。出60~240us的存在低脉冲,主机收到此信号表示复位成功。sbitio_DS18B20_DQ=P2^3#defineDS18B20_DQ_HIGHio_DS18B20_DQ=1;#defineDS18B20_DQ_LOWio_DS18B20_DQ=0;#defineDS18B20_DQ_READio_DS18B20_DQ uint8Temperature[4];voidv_Delay10Us_f(uint16Count{while(--Count{}}*******
温馨提示
- 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
- 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
- 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
- 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
- 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
- 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
- 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。
最新文档
- 加强出库效率的方案计划
- 2025年证券从业资格的挑战及对策试题及答案
- 国开2025年《人文英语3》综合任务答案
- 项目管理团队沟通的成功案例分析试题及答案
- 2025年特许金融分析师财务管理试题及答案
- 2025年注册会计师考试中立性试题及答案
- 2024-2025学年新高考数学一轮复习考点练:7.2《空间点、直线、平面之间的位置关系》 (含答案详解)教案
- 感染性疾病的早期检测方法研究试题及答案
- 中医儿科课题申报书
- 2025年证券从业资格证新动态试题及答案
- 单县烟草专卖局QC课题:多维度降低行政处罚文书出错率课件
- 2021抑郁症基层诊疗指南(最终版)解读
- 采购谈判的技巧案例
- 质量整改通知单(样板)
- 二子女无财产无债务离婚协议书
- 换填承载力计算(自动版)
- 公司董事会会议台账
- 2021-2022学年福建省厦门市第一中学高二下学期期中生物试题(原卷版)
- 煤矿安管人员七新题库及答案
- (完整word版)中小学教育质量综合评价指标框架(试行)
- HIV-1病毒载量测定及质量保证指南
评论
0/150
提交评论