单片机

1 引言

CAN,全称为“Controller Area Network”,即控制器局域网,是一种国际标准的,高性价的现场总线,在自动控制领域具有重要作用。CAN是一种多主方式的串行通讯总线,具有较高的实时性能,因此,广泛应用于汽车工业、航空工业、工业控制、安全防护等领域。

由于PC机无CAN接口,因此,PC机与智能节点构成CAN总线系统可采用RS232/CAN、并口/CAN、USB/CAN、ISA卡/CAN以及PCI卡/CAN方式接入。而采用RS232/CAN接入时,需采用CAN/RS232接口标准转换。针对这一问题,提出了CAN/RS232智能电平转换器设计方案,以SJAl000作为独立CAN控制器,完成CAN通信协议。并在SJAl000与驱动器之间连接高速光耦,从而实现总线各点间的电气隔离。

2 硬件电路设计

CAN/RS232智能电平转换器硬件电路主要由微处理器AT89C52、独立CAN通讯控制器SJAl000、CAN总线驱动器82C250、高速光电耦合器6N136、TTL电平与RS232电平转换器ICL232、LED数码管显示电路以及为SJAl000提供初始地址的拨码电路组成,其结构框图如图1所示。

基于单片机的智能电平转换器设计

3 CAN控制器SJAlOOO

SJAl000是一款独立CAN控制器,应用于移动目标和工业局域区域网控制领域。该器件是Philips公司CAN控制器PCA82C200的替代产品。SJAl000具有两种工作模式,本设计采用PeliCAN工作模式。

3.1 SJAl000与AT89C52的接口设计

SJAl000与AT89C52的接口电路如图2所示。AT89C52负责sJAl000的初始化,控制SJAl000来实现数据的接收和发送等通讯任务。SJAl000的ADO~AD7连接至AT89C52的P0端口,CS连接至AT89C52的P3.4(AT89C52的定时器T0不起作用)。当P3.4为0时,AT89C52选中SJAl000,并通过访问外部RAM低地址区实现P0端口的读/写操作,从而对SJAl000相应寄存器执行读/写操作。SJAl000的RD、WR、ALE引脚分别与AT89C52的对应引脚相连,SJAl000的INT引脚接AT89C52的INTO引脚。AT89C52还可通过中断方式访问SJAl000。为了增强系统的稳定性,采用双晶体振荡器,AT89C52采用11.059 2 MHz的晶体振荡器,SJAl000选用16 MHz的晶体振荡器。复位电路可选用DSl232,其输出引脚ARES与SRES分别与AT89C5l的RESET引脚和SJAl000的RESET引脚相连。

基于单片机的智能电平转换器设计

3.2 SJAl000与驱动器的连接

SJAl000的TX0、RX0引脚不是直接与82C250的TXD、RXD引脚相连,而是通过高速光耦6N136与82C250相连,这样可增强CAN总线节点的抗干扰能力,从而实现总线各节点间电气隔离。高速光耦6N136用于保护SJAl000型CAN总线控制器,该光耦两侧采用5 V的DC―DC电源.可使器件的VCC与VCCl完全隔离,提高系统的抗干扰能力以及节点的稳定性和安全性。图3所示为SJAl000与CAN驱动器82C250的连接电路。

基于单片机的智能电平转换器设计

4 软件程序设计

系统软件程序设计包括:主程序、CAN节点初始化子程序、RS232报文发送子程序、RS232报文接收子程序、CAN报文接收子程序以及CAN报文发送子程序。其主程序流程图如图4所示。

基于单片机的智能电平转换器设计

4.1 CAN节点初始化

独立CAN控制器SJAl000必须在上电或硬件复位后设置CAN通讯。上电后SJAl000的17引脚得到一个复位电平(低电平),使其进入复位模式。初始化包括设置工作方式、接收滤波方式、接收屏蔽寄存器和接收代码寄存器、波特率参数和中断允许寄存器。初始化设置完成后,SJAl000则进入工作状态,开始执行通讯任务。

SJAl000寄存器初始化,首先要将其模式寄存器(MOD)复位模式位置为l,再通过时钟分频寄存器(CDR)选择PeliCAN工作模式,同时关闭时钟输出(CLOCKOUT);通过中断允许寄存器(IER)开启发送中断、溢出中断和错误警告中断;向接收屏蔽寄存器(AMR)和接收代码(ACR)寄存器赋初值;通过总线定时寄存器0 (BTR0)和总线定时寄存器1(BTRl)设置波特率;为输出控制寄存器(OCR)赋初值;通过接收缓冲器起始地址寄存器(RBSA)来设置接收缓冲器FIF0的起始地址;清除发送错误计数寄存器(TXERR);清除错误代码捕捉寄存器(ECC),最后再次选择方式寄存器(MOD),设置单滤波,并返回工作状态。

4.2 RS232报文发送

AT89C52内含一组全双工串行传输界面,可同时接收或传输外部数据,其信号为TTL电平。由于与标准的RS232界面不兼容,须加电平准转换IC才可与RS232相连。AT89C52串行发送及接收数据均是通过特殊功能暂存器SBUF完成,在设定通讯协议模式后,通过指令“MOV SUBF,A”就可将存储在SBUF暂存器内的数据由引脚TXD串行传输。

4.3 RS232报文接收

AT89C52串行传输控制暂存器是由特殊控制暂存器SCON控制,SCON设定串行传输工作模式,发送接收时其第9位及发送接收时中断指示工作。通过指令“MOV A,SBUF”则将外界串行信号经由RXD引脚读入,并转换成并列数据存入暂存器A。

4.4 CAN报文发送

根据CAN协议,报文传输是由独立CAN控制器SJAl000完成。主控制器必须将要发送的数据按特定格式组合成一帧报文传输到发送缓冲器,将命令寄存器中的“发送请求”置1,然后启动SJAl000发送即可。

4.5 CAN报文接收

CAN报文接收子程序负责节点的报文接收和其他情况的处理。接收子程序在结构上要比发送子程序复杂一些,因为在接收报文时,要对同处理诸如总线关闭、错误报警、接收溢出等情况。SJAl000报文接收和发送有两种方式:中断方式和查询方式。查询方式应禁止接收中断使能,而中断方式一般用于实时性要求较高的情况。

在中断方式下,如果SJAl000已接收一个报文,而且报文通过验收滤波器并存入接收FIFO,则产生一个接收中断。因此主控制器立刻工作,将收到的报文发送到报文存储器中,再通过置位命令寄存器的相应标志“RRB”发送一个释放接收缓冲器命令。接收FIF0里的更多报文将产生一个新的接收中断,因此不能将所有接收FIF0中的有效信息在一个中断周期内读出。接收缓冲器释放后,SJAl000会检查状态寄存器中接收缓冲器状态(RBS)是否有更多报文,所有有效信息都将循环读出。

5 结语

本系统设计采用SJAl000作为CAN独立控制器,以CAN/RS232智能电平转换器为实例,论述了CAN总线与单片机之间的接口连接,对CAN总线的实际应用具有一定的参考价值。

来源: eeworld.com

围观 361

对程序进行优化,通常是指优化程序代码或程序执行速度。优化代码和优化速度实际上是一个予盾的统一,一般是优化了代码的尺寸,就会带来执行时间的增加,如果优化了程序的执行速度,通常会带来代码增加的副作用,很难鱼与熊掌兼得,只能在设计时掌握一个平衡点。

一、程序结构的优化

1、程序的书写结构

虽然书写格式并不会影响生成的代码质量,但是在实际编写程序时还是应该尊循一定的书写规则,一个书写清晰、明了的程序,有利于以后的维护。在书写程序时,特别是对于While、for、do…while、if…elst、switch…case 等语句或这些语句嵌套组合时,应采用“缩格”的书写形式,

2、标识符

程序中使用的用户标识符除要遵循标识符的命名规则以外,一般不要用代数符号(如a、b、x1、y1)作为变量名,应选取具有相关含义的英文单词(或缩写)或汉语拼音作为标识符,以增加程序的可读性,如:

count、number1、red、work 等。

3、程序结构

C 语言是一种高级程序设计语言,提供了十分完备的规范化流程控制结构。因此在采用C 语言设计 单片机应用系统程序时,首先要注意尽可能采用结构化的程序设计方法,这样可使整个应用系统程序结构清晰,便于调试和维护。于一个较大的应用程序,通常将整个程序按功能分成若干个模块,不同模块完成不同的功能。各个模块可以分别编写,甚至还可以由不同的程序员编写,一般单个模块完成的功能较为简单,设计和调试也相对容易一些。在C 语言中,一个函数就可以认为是一个模块。所谓程序模块化,不仅是要将整个程序划分成若干个功能模块,更重要的是,还应该注意保持各个模块之间变量的相对独立性,即保持模块的独立性,尽量少使用 全局变量等。对于一些常用的功能模块,还可以 封装为一个应用程序库,以便需要时可以直接调用。但是在使用模块化时,如果将模块分成太细太小,又会导致程序的执行效率变低(进入和退出一个函数时保护和恢复寄存器占用了一些时间)。

4、定义常数

在程序化设计过程中,对于经常使用的一些常数,如果将它直接写到程序中去,一旦常数的数值发生变化,就必须逐个找出程序中所有的常数,并逐一进行修改,这样必然会降低程序的可维护性。因此,应尽量当采用预处理命令方式来定义常数,而且还可以避免输入错误。

5、减少判断语句

能够使用条件编译(ifdef)的地方就使用条件编译而不使用if 语句,有利于减少编译生成的代码的长度。

6、表达式

对于一个表达式中各种运算执行的优先顺序不太明确或容易混淆的地方,应当采用圆括号明确指定它们的优先顺序。一个表达式通常不能写得太复杂,如果表达式太复杂,时间久了以后,自己也不容易看得懂,不利于以后的维护。

7、函数

对于程序中的函数,在使用之前,应对函数的类型进行说明,对函数类型的说明必须保证它与原来定义的函数类型一致,对于没有参数和没有返回值类型的函数应加上“void”说明。如果果需要缩短代码的长度,可以将程序中一些公共的程序段定义为函数,在Keil 中的高级别优化就是这样的。如果需要缩短程序的执行时间,在程序调试结束后,将部分函数用宏定义来代替。注意,应该在程序调试结束后再定义宏,因为大多数编译系统在宏展开之后才会报错,这样会增加排错的难度。

8、尽量少用全局变量,多用局部变量。因为全局变量是放在数据存储器中,定义一个全局变量,MCU 就少一个可以利用的数据存储器空间,如果定义了太多的全局变量,会导致编译器无足够的内存可以分配。而局部变量大多定位于MCU 内部的寄存器中,在绝大多数MCU 中,使用寄存器操作速度比数据存储器快,指令也更多更灵活,有利于生成质量更高的代码,而且局部变量所的占用的寄存器和数据存储器在不同的模块中可以重复利用。

9、设定合适的编译程序选项

许多编译程序有几种不同的优化选项,在使用前应理解各优化选项的含义,然后选用最合适的一种优化方式。通常情况下一旦选用最高级优化,编译程序会近乎病态地追求代码优化,可能会影响程序的正确性,导致程序运行出错。因此应熟悉所使用的编译器,应知道哪些参数在优化时会受到影响,哪些参数不会受到影响。

在ICCAVR 中,有“Default”和“Enable Code Compression”两个优化选项。

在CodeVisionAVR 中,“Tiny”和“small”两种内存模式。

在IAR ==有7 种不同的内存模式选项。

在GCCAVR 中优化选项更多,一不小心更容易选到不恰当的选项。

二、代码的优化

1、选择合适的算法和数据结构

应该熟悉算法语言,知道各种算法的优缺点,具体资料请参见相应的参考资料,有很多计算机书籍上都有介绍。将比较慢的顺序查找法用较快的二分查找或乱序查找法代替,插入排序或冒泡排序法用快速排序、合并排序或根排序代替,都可以大大提高程序执行的效率。.选择一种合适的数据结构也很重要,比如你在一堆随机存放的数中使用了大量的插入和删除指令,那使用链表要快得多。

数组与指针具有十分密码的关系,一般来说,指针比较灵活简洁,而数组则比较直观,容易理解。对于大部分的编译器,使用指针比使用数组生成的代码更短,执行效率更高。但是在Keil 中则相反,使用数组比使用的指针生成的代码更短。

2、使用尽量小的数据类型

能够使用字符型(char)定义的变量,就不要使用整型(int)变量来定义;能够使用整型 变量定义的变量就不要用长整型(long int),能不使用浮点型(float)变量就不要使用浮点型变量。当然,在定义变量后不要超过变量的作用范围,如果超过变量的范围赋值,C 编译器并不报错,但程序运行结果却错了,而且这样的错误很难发现。在ICCAVR 中,可以在Options 中设定使用printf 参数,尽量使用基本型参数(%c、%d、%x、%X、%u 和%s 格式说明符),少用长整型参数(%ld、%lu、%lx 和%lX 格式说明符),至于浮点型的参数(%f)则尽量不要使用,其它C 编译器也一样。在其它条件不变的情况下,使用%f 参数,会使生成的代码的数量增加很多,执行速度降低。

3、使用自加、自减指令

通常使用自加、自减指令和复合赋值表达式(如a-=1 及a+=1 等)都能够生成高质量的程序代码,编译器通常都能够生成inc 和dec 之类的指令,而使用a=a+1 或a=a-1 之类的指令,有很多C 编译器都会生成二到三个字节的指令。在AVR 单片适用的ICCAVR、GCCAVR、IAR 等C 编译器以上几种书写方式生成的代码是一样的,也能够生成高质量的inc 和dec 之类的的代码。

4、减少运算的强度

可以使用运算量小但功能相同的表达式替换原来复杂的的表达式。如下:

(1)、求余运算。

a=a%8;

可以改为:

a=a&7;

说明:位操作只需一个 指令周期即可完成,而大部分的C 编译器的“%”运算均是调用子程序来完成,代码长、执行速度慢。通常,只要求是求2n 方的余数,均可使用位操作的方法来代替。

(2)、平方运算

a=pow(a,2.0);

可以改为:

a=a*a;

说明:在有内置硬件乘法器的单片机中(如51 系列),乘法运算比求平方运算快得多,因为 浮点数的求平方是通过调用子程序来实现的,在自带硬件乘法器的AVR 单片机中,如ATMega163 中,乘法运算只需2 个时钟周期就可以完成。既使是在没有内置硬件乘法器的AVR 单片机中,乘法运算的子程序比平方运算的子程序代码短,执行速度快。

如果是求3 次方,如:

a=pow(a,3.0);

更改为:

a=a*a*a;

则效率的改善更明显。

(3)、用移位实现乘除法运算

a=a*4;

b=b/4;

可以改为:

a=a<<2;

b=b>>2;

说明:通常如果需要乘以或除以2n,都可以用移位的方法代替。在ICCAVR 中,如果乘以2n,都可以生成左移的代码,而乘以其它的整数或除以任何数,均调用乘除法子程序。用移位的方法得到代码比调用乘除法子程序生成的代码效率高。实际上,只要是乘以或除以一个整数,均可以用移位的方法得到结果,如:

a=a*9

可以改为:

a=(a<<3)+a

5、循环

(1)、循环语

对于一些不需要循环变量参加运算的任务可以把它们放到循环外面,这里的任务包括表达式、函数的调用、指针运算、数组访问等,应该将没有必要执行多次的操作全部集合在一起,放到一个init 的初始化程序中进行。

(2)、延时函数:

通常使用的延时函数均采用自加的形式:

  void delay (void)

  {

  unsigned int i;

  for (i=0;i<1000;i++);

  }

  将其改为自减延时函数:

  void delay (void)

  {

  unsigned int i;

  for (i=1000;i>0;i--);

  }

两个函数的延时效果相似,但几乎所有的C 编译对后一种函数生成的代码均比前一种代码少1~3 个字节,因为几乎所有的MCU 均有为0 转移的指令,采用后一种方式能够生成这类指令。

在使用while 循环时也一样,使用自减指令控制循环会比使用自加指令控制循环生成的代码更少1~3 个字母。

但是在循环中有通过循环变量“i”读写数组的指令时,使用预减循环时有可能使数组超界,要引起注意。

(3)while 循环和do…while 循环

用while 循环时有以下两种循环形式:

  unsigned int i;

  i=0;

  while (i<1000)

  {

  i++;

  //用户程序

  }

  或:

  unsigned int i;

  i=1000;

  do

  i--;

  //用户程序

  while (i>0);

在这两种循环中,使用do…while 循环编译后生成的代码的长度短于while 循环。

6、查表

在程序中一般不进行非常复杂的运算,如浮点数的乘除及开方等,以及一些复杂的数学模型的插补运算,对这些即消耗时间又消费资源的运算,应尽量使用查表的方式,并且将数据表置于程序存储区。如果直接生成所需的表比较困难,也尽量在启动时先计算,然后在数据存储器中生成所需的表,后以在程序运行直接查表就可以了,减少了程序执行过程中重复计算的工作量。

7、其它

比如使用在线汇编及将字符串和一些常量保存在程序存储器中,均有利于优化

围观 544

计算机技术,尤其是单片机技术和大规模集成电路及各种新型传感元件的迅速发展和日臻成熟,微机技术在电力系统中的普及应用,使电力系统的测量和监控技术得到了快速的发展。在工业生产过程中,往往需要对电动机运行期间的功率因数进行检测,以便采取相应的补偿措施来提高功率因数,从而达到节约电能的目的。若三相负载不平衡,为能比较真实地反映三相电机的功率因数值,可通过采样三相交流电中任意一相相电流以及另外两相线电压之间的相位差得到三相系统的功率因数。MSP430系列单片机是一种超低功耗的混合信号处理器(Mixed Signal Processor),它具有低电压、超低功耗、强大的处理能力、系统工作稳定、丰富的片内外设、方便开发等优点,具有很高的性价比,在工程控制等领域有着极其广泛的应用范围。使用MSP430实现对电机功率因数等电力参数的测量,不但提高了测量的精度和自动化水平,而且降低了系统的功耗。

1 功率因数与相位

电机的功率因数cosΦ值是相电压与相电流的余弦值。设三相的电压分别为UA,UB,UC,电流分别为IA,IB,IC,则它们的表达式如下:

基于MSP430的电机功率因数的测量系统

上式中:UM表示每相电压幅值;IM表示每相电流幅值;ω表示角频率;Φ表示相电流滞后相电压的相位差角。图1给出了三相输电线路的相电压、相电流的矢量图。
基于MSP430的电机功率因数的测量系统
对于三相对称的电源,若电机的功率因数为1,即等效总负载为纯阻性,则各相电源的相电流必定与其相电压同相,相位差Φ=0°,而当电机的功率因数值不为1时,电流向量与电压向量之间将存在一定的夹角Φ,感性负载时Φ角滞后0°~90°,容性负载时角超前0°~-90°。因此准确检测线电压与线电流之间的相位差,即可测量出电机的功率因数角。

2 相位差Φ计算原理

相位差Φ的计算原理是利用输入2路信号过零点的时间差,以及信号的频率来计算2路信号的相位差。

2.1 频率的测量

首先测量单路输入信号频率,方法是记录1路方波信号2次连续上升沿触发的定时器计数值t1和t2,计算出2次上升沿计数器差值△t=t1-t2,以定时器工作频率fclk为参考,求出输入信号的频率为Fin=fclk/△N1。

2.2 信号相位差的测量

运用TI的MSP430F449的捕获功能,捕获2路信号的过零点,记录定时器这一时刻的计算值,计算出它们之间的时间差。TI公司的所有的FLASH型单片机都含有Timer_A,它是程序的核心。Timer_A由1个16位定时器和多路比较/捕获通道组成。

2路信号的相位差△=360°×△t/Ti,其中,△t=△N2/flk,△N2为2路信号的上升沿分别触发计数器的差值;Ti为输入信号的周期。由相位差的计算可简化为:

基于MSP430的电机功率因数的测量系统

3系统硬件结构

测量系统以MSP430F449单片机为核心,主要由电压电流检测电路、信号调理电路、时钟电路、电源电路和显示电路组成。其系统结构图如图2所示。

基于MSP430的电机功率因数的测量系统

3.1 电压、电流检测电路

为实现强、弱电的隔离,提高抗干扰能力,检测逆变器供电条件下的相电流以及两相的线电压,分别采用电流互感器和电压互感器。由于逆变器供电不平衡,造成三相交流电压、交流电流相位差不一致,影响功率因数测量的最终因数是相位,除频率变化造成的相位改变外,还有互感器的相差及交流采样时电流和电压不能同步采样造成的相差,这些因素造成的相差实际上是一个常数。

3.2 信号调理电路

电流互感器的输出,经运算放大器和I/V转换器,把电流信号转换成电压信号。电压信号和电流信号转化的电压信号进行放大、施密特整形,把交流信号转化为方波信号,输入到单片机Timer_A的TA1,TA2输入端。这样测信号相移就变成测信号边沿之间的时间宽度问题,MSP430F449单片机很容易实现。

3.3 时钟电路

时钟电路用于产生单片机工作所需的时钟信号,该系统采用内部时钟模块,外接晶振方式,振荡频率主要由石英晶振的频率决定。单片机内部具有时钟模块,能实现超低功耗应用。振荡器和系统时钟发生器的主要设计目标是廉价和低功耗。为达到系统廉价,外接器件缩减到只有一个普通晶振。在数字系统中,系统功耗与频率成正比,所以使用低频晶体和和含有倍频器的振荡器可以满足时钟系统速度与低功耗这2个要求。该系统的时钟电路是用一频率为32 768 Hz的晶振来固定整个电路的频率来实现。

3.4 显示电路

MSP430F449带有内部LCD驱动模块,直接将液晶显示屏连接在芯片的驱动端口即可,电路结构极为简单。LCD具有功耗低、体积小、质量轻、超薄和可编程驱动等其他显示无法比拟的优点。由点阵液晶显示器件与相应的控制器、驱动器装配成的显示模块的种类较多,其功能、指令、接口定义及引脚并无统一标准,具体使用时应加以选择。

4 软件设计

MSP430F449单片机内部具有多个时钟源,可以灵活地配置给各模块使用以及工作于多种低功耗模式,降低控制电路的功耗提高整体效率,其具有内部自带有高精度12为ADC12、一个集成LCD驱动模块、硬件乘法器以及Timer_A和Timer_B定时器等。

相电压和相电流的相位差Φ测量程序由主程序和中断程序组成。主程序完成各程控器件初始化、清零显示器、设定时钟频率等功能,然后进入低功耗模式,等待相位测量中断。中断服务程序完成频率、相位差的测量。其流程图如图3所示。

基于MSP430的电机功率因数的测量系统

此系统的软件是在IAR Embedded Workbench开发环境下采用C语言编写的,采用模块化程序设计。测量功能由中断完成的优点是使单片机绝大部分时间处于低功耗状态,充分发挥了MSP430系列单片机微功耗特点,降低了仪器的功耗。相位的测量需要对输入信号的周期和相位差值分别采样,周期的采样使用CCR0来捕获同一输入信号相邻的2个周期的上升沿,在第一个上升沿到来时触发CCR0中断,清零计数器并开始计数;当第二个上升沿到来时再次触发中断,保存计数值。为了防止中断冲突,提高测量的精度,采用滞后捕获的方法。即电流信号上升沿到来时,禁止CCR0,一直等到CCR2捕获到电流信号的上升沿为止,这时捕获到的2个上升沿不在同一个周期内,由于实测计数值和实际相位差计数值两者之间的差值为整数倍,从而能够得用已测到周期值算出2路信号相位差的实际计数值。为了提高测量的精废要求,可以在程序中使用长度为20的样本循环队列,而每个样本是40次周期采样和60次相位差采样的平均值。

5 结语

经实践证明,采用MsP430单片机技术对电机功率因数进行高精度测量,既可以改变传统的测量方法,同时又能实现电机功率因数的在线检测,对提高电机的运行,改善其性能起到一定的作用。由于采用测量单相电流及电压之间的相位差来得到三相系统的功率因数的检测方法,无需判断相序,可适用于不同的电机接线方法,在实际应用场合工作稳定可靠。MSP430F449单片机超低功耗存储量大,工作电压非常低,只要1.8~3.6 V即可以工作,十分适用于电池供电的工频数字相位测量。该测量系统的相位测量绝对误差≤2°,具有频率测量及数字显示功能;相位差数字显示的相位读数为0°~180.0°,分辨率为0.1°

转自: 华强电子网

围观 332

单片机运行时的数据都存在于RAM(随机存储器)中,在掉电后RAM 中的数据是无法保留的,那么怎样使数据在掉电后不丢失呢?这就需要使用EEPROM 或FLASHROM 等存储器来实现。

插播一段:ROM最初不能编程,出厂什么内容就永远什么内容,不灵活。后来出现了PROM,可以自己写入一次,要是写错了,只能换一片。随着不断改进,终于出现了可多次擦除写入的EPROM,每次擦除要把芯片拿到紫外线上照一下,想一下你往单片机上下了一个程序之后发现有个地方需要加一句话,为此你要把单片机放紫外灯下照半小时,然后才能再下一次,这么折腾一天也改不了几次。历史的车轮不断前进,伟大的EEPROM出现了,拯救了一大批程序员,终于可以随意的修改ROM中的内容了。

EEPROM的全称是“电可擦除可编程只读存储器”,即Electrically Erasable Programmable Read-Only Memory。是相对于紫外擦除的rom来讲的。但是今天已经存在多种EEPROM的变种,变成了一类存储器的统称。

狭义的EEPROM:

这种rom的特点是可以随机访问和修改任何一个字节,可以往每个bit中写入0或者1。这是最传统的一种EEPROM,掉电后数据不丢失,可以保存100年,可以擦写100w次。具有较高的可靠性,但是电路复杂/成本也高。因此目前的EEPROM都是几十千字节到几百千字节的,绝少有超过512K的。

Flash:

Flash属于广义的EEPROM,因为它也是电擦除的ROM。但是为了区别于一般的按字节为单位的擦写的EEPROM,我们都叫它Flash。

既然两者差不多,为什么单片机中还要既有Flash又有EEPROM呢?

通常,单片机里的Flash都用于存放运行代码,在运行过程中不能改;EEPROM是用来保存用户数据,运行过程中可以改变,比如一个时钟的闹铃时间初始化设定为12:00,后来在运行中改为6:00,这是保存在EEPROM里,不怕掉电,就算重新上电也不需要重新调整到6:00。

但最大区别是其实是:FLASH按扇区操作,EEPROM则按字节操作,二者寻址方法不同,存储单元的结构也不同,FLASH的电路结构较简单,同样容量占芯片面积较小,成本自然比EEPROM低,因而适合用作程序存储器,EEPROM则更多的用作非易失的数据存储器。当然用FLASH做数据存储器也行,但操作比EEPROM麻烦的多,所以更“人性化”的MCU设计会集成FLASH和EEPROM两种非易失性存储器,而廉价型设计往往只有 FLASH,早期可电擦写型MCU则都是EEPRM结构,现在已基本上停产了。

在芯片的内电路中,FLASH和EEPROM不仅电路不同,地址空间也不同,操作方法和指令自然也不同,不论冯诺伊曼结构还是哈佛结构都是这样。技术上,程序存储器和非易失数据存储器都可以只用FALSH结构或EEPROM结构,甚至可以用“变通”的技术手段在程序存储区模拟“数据存储区”,但就算如此,概念上二者依然不同,这是基本常识问题。

EEPROM:电可擦除可编程只读存储器,Flash的操作特性完全符合EEPROM的定义,属EEPROM无疑,首款Flash推出时其数据手册上也清楚的标明是EEPROM,现在的多数Flash手册上也是这么标明的,二者的关系是“白马”和“马”。至于为什么业界要区分二者,主要的原因是 Flash EEPROM的操作方法和传统EEPROM截然不同,次要的原因是为了语言的简练,非正式文件和口语中Flash EEPROM就简称为Flash,这里要强调的是白马的“白”属性而非其“马”属性以区别Flash和传统EEPROM。

Flash的特点是结构简单,同样工艺和同样晶元面积下可以得到更高容量且大数据量下的操作速度更快,但缺点是操作过程麻烦,特别是在小数据量反复重写时,所以在MCU中Flash结构适于不需频繁改写的程序存储器。

很多应用中,需要频繁的改写某些小量数据且需掉电非易失,传统结构的EEPROM在此非常适合,所以很多MCU内部设计了两种EEPROM结构,FLASH的和传统的以期获得成本和功能的均衡,这极大的方便了使用者。随着ISP、IAP的流行,特别是在程序存储地址空间和数据存储地址空间重叠的MCU系中,现在越来越多的MCU生产商用支持IAP的程序存储器来模拟EEPROM对应的数据存储器,这是低成本下实现非易失数据存储器的一种变通方法。为在商业宣传上取得和双EEPROM工艺的“等效”性,不少采用Flash程序存储器“模拟”(注意,技术概念上并非真正的模拟)EEPROM数据存储器的厂家纷纷宣称其产品是带EEPROM的,严格说,这是非常不严谨的,但商人有商人的目的和方法,用Flash“模拟”EEPROM可以获取更大商业利益,所以在事实上,技术概念混淆的始作俑者正是他们。

从成本上讲,用Flash“模拟”EEPROM是合算的,反之不会有人干,用EEPROM模拟Flash是怎么回事呢?这可能出在某些程序存储空间和数据存储空间连续的MCU上。这类MCU中特别是存储容量不大的低端MCU依然采用EEPROM作为非易失存储器,这在成本上反而比采用Flash和传统EEPROM双工艺的设计更低,但这种现象仅仅限于小容量前提下。因Flash工艺的流行,现在很多商人和不够严谨的技术人员将程序存储器称为Flash,对于那些仅采用传统EEPROM工艺的MCU而言,他们不求甚解,故而错误的将EEPROM程序存储器称为“ 模拟Flash”,根本的原因是他们未理解Flash只是一种存储器结构而非存储器的用途,错误的前提自然导致错误的结论。商业上讲,用EEPROM模拟 Flash是不会有人真去做的愚蠢行为,这违背商业追求最大利益的原则,技术上也不可行,而对于技术人员而言。本质的问题是Flash是一种存储器类型而非MCU中的程序存储器,即使MCU的程序存储器用的是Flash,但其逆命题不成立。

转自: 自由石匠

围观 1170

单片机常见的报警方式有6种,如以下所示:

(1)指示灯或数码管显示出数据,以提醒操作人员注意。

(2)采用声、光及语音进行报警。其中,光效果通常取自发光二极管LED或其他光源器件;声效果可取自电铃、电笛、蜂鸣器、或音乐(语音)芯片等。

(3)合成语音报警。采用这种方式进行报警时,单片机应用系统将对语音信号进行采集、处理、合成和识别,使报警系统的功能更加完善,报警信息更加具体、生动、准确,直至给出报警对象的具体信息。

(4)图形、图像报警。这种系统设微型机控制的打印机或CRT显示器,使警卫人员在接受其他报警信号的同时,还能看到报警显示的画面或数据、文字,不但能将报警资料打印成文,而且可方便存档。

(5)具有控制功能的报警。这种报警系统具有控制功能,如:适时将自动操作切换到人工操作,防止事故发生;达到报警限时,执行机构动作;自动拨出电话号码,将警报情况报告给有关人员。

(6)具有信号远传功能的报警。能将报警信号远传至信号可以达到的远距离处,以供监视、控制用。常用的信号远传方法有:红外线、激光、微波、超声波、有线载波、无线电传输等。.

利用单片机应用系统进行报警的常用方法是什么?

常用的方法就是把采集到的数据送到单片机应用系统进行处理,与该参数的上、下限给定值进行比较,若超过给定值时则进行报警,否则,就作为正常值进行显示或控制。

在单片机报警系统中,发光二极管常用何种型号的集成电路驱动?

由于发光二极管的驱动电流在20~30mA,所以不能用TTL门电路的输出直接启动。在单片机报警系统中,发光二极管常见的驱动方法是采用OC门进行驱动,如74LS06或74LS07等型号的OC门。

单片机报警系统有哪两种程序设计方法?

依据报警参数和传感器划分,简单的报警程序可分为两种:一种是全软件报警程序,另一种是硬件申请,软件处理报警程序。

怎样使用全软件报警程序的方法实现报警?

全软件件报警程序的基本方法是:作业现场的被测参数经传感器、变送器、模/数转换器送到单片机后,再与规定的上、下限给定值相比较,根据比较的结果进行报警或处理,其整个过程都由软件实现。

怎样用硬件申请、软件处理报警程序的方法实现报警?

使用这种报警方法时,报警要求不是通过程序比较法得到的,而是直接由传感器产生的。在发现警性,传感器发出报警要求之后,立即向CPU提出中断申请,CPU响应中断后,立刻进入中断服务程序,实现报警或对参数、位置实现监控。例如:电接点压力式报警,吊车的限位控制等。

报警程序根据系统中的参数的要求,可以分为哪两种程序?

报警程序根据系统和参数的要求,可以分为简单的越限报警和报警处理程序两种。

来源:网络
本文仅供学习参考使用,版权归原作者所有

围观 249

STM32中的内存

STM32中的内存包含两块主要区域:flash memory(只读)、static ram memory(SRAM,读写)。其中,flash memory 起始于0x08000000,SRAM起始于0x20000000。flash memory的第一部分存放异常向量表,表中包含了指向各种异常处理程序的指针。比如说,RESET Handler便位于0x08000004的位置,在处理器上电或重启时执行。在0x08000000处存放的是内部栈指针。

STM32的存储器映射如下图所示:

STM32单片机是如何启动的?

程序执行时,机器代码位于flash区域,变量和运行时栈等易变的内容位于SRAM中。

startup.s

下面看一下start.s的代码,了解下如何定义不同类型的代码。

Stack_Size      EQU     x400           ;定义一个变量Stack_Size,相当于 Stack_Size = x400

                AREA    STACK, NOINIT, READWRITE, ALIGN=3   ;定义一个segment 命名为 STACK
Stack_Mem       SPACE   Stack_Size      ;连续x400个字节清零
__initial_sp


; <h> Heap Configuration
;   <o>  Heap Size (in Bytes) <x0-xFFFFFFFF:8>
; </h>

Heap_Size      EQU     x200

                AREA    HEAP, NOINIT, READWRITE, ALIGN=3
__heap_base
Heap_Mem        SPACE   Heap_Size
__heap_limit

这段代码中主要是定义了两个段(segment),这两个段都是可读写的,涉及到两个汇编指令AREA和SPACE。

• AREA

语法:

AREA sectionname{,attr}{,attr}...

where: sectionname is the name to give to the section. Sections are independent, named, indivisible chunks of code or data that are manipulated by the linker.

当遇到下一个AREA时,表示该段结束。或者是,碰到END也表示该段结束。

AREA属性:

NOINIT 该数据段无须初始化

READWRITE 可读写

DATA 数据而非指令,默认是可读写的

ALIGN 对齐

• SPACE

语法:

{label} SPACE expr

The SPACE directive reserves a zeroed block of memory.

保留了一段零初始化的内存

紧接着,定义了一个RESET段,该段只读的数据段,该段主要包含异常向量表。异常向量表的每一个元素都是一个函数地址,CDC表示一个字长的整形数据。向量的第一个元素是栈顶地址,第二个元素是Reset_Handler。

PRESERVE8
                THUMB


; Vector Table Mapped to Address 0 at Reset
                AREA    RESET, DATA, READONLY
                EXPORT  __Vectors
                EXPORT  __Vectors_End
                EXPORT  __Vectors_Size

__Vectors       DCD     __initial_sp               ; Top of Stack
                DCD     Reset_Handler              ; Reset Handler
                DCD     NMI_Handler                ; NMI Handler

                /******后面代码省略********/

定义完向量表之后,又定义了.text段,也就是存放程序代码段,该段也是只读的。

该段定义了向量表中的各个处理程序,每个程序以PROC开始,以ENDP结束。第一个是Reset_Handler处理函数,单片机器动时便是从这里开始执行的。我们可以看到,除了ResetHandler其他的函数都只有一个 "B ."这是一个空的跳转,相当于进了死循环,所以需要在外部定义相应的处理函数。

Reset_Handler函数首先执行函数SystemInit,完成硬件初始化工作,然后执行__main建立C运行环境并从中调到用户定义的main()函数执行。

AREA    |.text|, CODE, READONLY

; Reset handler
Reset_Handler    PROC
                 EXPORT  Reset_Handler             [WEAK]
        IMPORT  SystemInit
        IMPORT  __main

                 LDR     R0, =SystemInit
                 BLX     R0
                 LDR     R0, =__main
                 BX      R0
                 ENDP

; Dummy Exception Handlers (infinite loops which can be modified)

NMI_Handler     PROC
                EXPORT  NMI_Handler                [WEAK]
                B       .
                ENDP

下载程序到单片机

startup.s汇编程序经过汇编器编译后,产生目标代码,然后通过链接器将各个子程序链接为可执行代码。在链接之前,目标代码中的地址都是相对地址,只有链接之后才能转变为可执行的目标代码。在链接过程中,会确定每一部分代码的地址。这个过程都被IDE封装起来了,所以用户看不到。

链接过程中,不同的段的地址是不一样的,比如可读写的段必须放在SRAM对应的地址中(0x20000000开始),只读的段放到flash中(0x08000000开始)。我们可以在keil开发环境的Linker选项面板中看到读写和只读存放的地址,如下图所示。

STM32单片机是如何启动的?

下载到单片机时,也是分别制定了RAM和flash的地址,下图所示。
STM32单片机是如何启动的?

来源: Linux公社

围观 415

近年来,在单片机系统中嵌入操作系统已经成为人们越来越关心的一个话题。本文通过对一种源码公开的单片机嵌入式实时操作系统μC/OS-II为例,阐述了在单片机中使用该嵌入式操作系统的优缺点,以及在应用中应当注意的一些问题。

早在20世纪60年代,就已经有人开始研究和开发嵌入式操作系统。但直到最近,它才在国内被越来越多的提及,在通信、电子、自动化等需要实时处理的领域所日益显现的重要性吸引了人们越来越多的注意力。但是,人们所谈论的往往是一些著名的商业内核,诸如VxWorks、PSOS等。这些商业内核性能优越,但价格昂贵,主要用于16位和32位处理器中,针对国内大部分用户使用的51系列8位单片机,可以选择免费的μC/OS-II。

μC/OS-II的特点

1、μC/OS-II是由Labrosse先生编写的一个开放式内核,最主要的特点就是源码公开。这一点对于用户来说可谓利弊各半,好处在于,一方面它是免费的,另一方面用户可以根据自己的需要对它进行修改。缺点在于它缺乏必要的支持,没有功能强大的软件包,用户通常需要自己编写驱动程序,特别是如果用户使用的是不太常用的单片机,还必须自己编写移植程序。

2、μC/OS-II是一个占先式的内核,即已经准备就绪的高优先级任务可以剥夺正在运行的低优先级任务的CPU使用权。这个特点使得它的实时性比非占先式的内核要好。通常我们都是在中断服务程序中使高优先级任务进入就绪态(例如发信号),这样退出中断服务程序后,将进行任务切换,高优先级任务将被执行。拿51单片机为例,比较一下就可以发现这样做的好处。假如需要用中断方式采集一批数据并进行处理,在传统的编程方法中不能在中断服务程序中进行复杂的数据处理,因为这会使得关中断时间过长。所以经常采用的方法是置一标志位,然后退出中断。由于主程序是循环执行的,所以它总有机会检测到这一标志并转到数据处理程序中去。但是因为无法确定发生中断时程序到底执行到了什么地方,也就无法判断要经过多长时间数据处理程序才会执行,中断响应时间无法确定,系统的实时性不强。如果使用μC/OS-II的话,只要把数据处理程序的优先级设定得高一些,并在中断服务程序中使它进入就绪态,中断结束后数据处理程序就会被立即执行。这样可以把中断响应时间限制在一定的范围内。对于一些对中断响应时间有严格要求的系统,这是必不可少的。但应该指出的是如果数据处理程序简单,这样做就未必合适。因为μC/OS-II要求在中断服务程序末尾使用OSINTEXIT函数以判断是否进行任务切换,这需要花费一定的时间。

3、μC/OS-II和大家所熟知的Linux等分时操作系统不同,它不支持时间片轮转法。μC/OS-II是一个基于优先级的实时操作系统,每个任务的优先级必须不同,分析它的源码会发现,μC/OS-II把任务的优先级当做任务的标识来使用,如果优先级相同,任务将无法区分。进入就绪态的优先级最高的任务首先得到CPU的使用权,只有等它交出CPU的使用权后,其他任务才可以被执行。所以它只能说是多任务,不能说是多进程,至少不是我们所熟悉的那种多进程。显而易见,如果只考虑实时性,它当然比分时系统好,它可以保证重要任务总是优先占有CPU。但是在系统中,重要任务毕竟是有限的,这就使得划分其他任务的优先权变成了一个让人费神的问题。另外,有些任务交替执行反而对用户更有利。例如,用单片机控制两小块显示屏时,无论是编程者还是使用者肯定希望它们同时工作,而不是显示完一块显示屏的信息以后再显示另一块显示屏的信息。这时候,要是μC/OS-II即支持优先级法又支持时间片轮转法就更合适了。

4、μC/OS-II对共享资源提供了保护机制。正如上文所提到的,μC/OS-II是一个支持多任务的操作系统。一个完整的程序可以划分成几个任务,不同的任务执行不同的功能。这样,一个任务就相当于模块化设计中的一个子模块。在任务中添加代码时,只要不是共享资源就不必担心互相之间有影响。而对于共享资源(比如串口),μC/OS-II也提供了很好的解决办法。一般情况下使用的是信号量的方法。简单地说,先创建一个信号量并对它进行初始化。当一个任务需要使用一个共享资源时,它必须先申请得到这个信号量,而一旦得到了此信号量,那就只有等使用完了该资源,信号量才会被释放。在这个过程中即使有优先权更高的任务进入了就绪态,因为无法得到此信号量,也不能使用该资源。这个特点的好处显而易见,例如当显示屏正在显示信息的时候,外部产生了一个中断,而在中断服务程序中需要显示屏显示其他信息。这样,退出中断服务程序后,原有的信息就可能被破坏了。而在μC/OS-II中采用信号量的方法时,只有显示屏把原有信息显示完毕后才可以显示新信息,从而可以避免这个现象。不过,采用这种方法是以牺牲系统的实时性为代价的。如果显示原有信息需要耗费大量时间,系统只好等待。从结果上看,等于延长了中断响应时间,这对于未显示信息是报警信息的情况,无疑是致命的。发生这种情况,在μC/OS-II中称为优先级反转,就是高优先级任务必须等待低优先级任务的完成。在上述情况下,在两个任务之间发生优先级反转是无法避免的。所以在使用μC/OS-II时,必须对所开发的系统了解清楚,才能决定对于某种共享资源是否使用信号量。

μC/OS-II在单片机使用中的一些特点:

(1)在单片机系统中嵌入μC/OS-II将增强系统的可靠性,并使得调试程序变得简单。以往传统的单片机开发工作中经常遇到程序跑飞或是陷入死循环。可以用看门狗解决程序跑飞问题,而对于后一种情况,尤其是其中牵扯到复杂数学计算的话,只有设置断点,耗费大量时间来慢慢分析。如果在系统中嵌入μC/OS-II的话,事情就简单多了。可以把整个程序分成许多任务,每个任务相对独立,然后在每个任务中设置超时函数,时间用完以后,任务必须交出CPU的使用权。即使一个任务发生问题,也不会影响其他任务的运行。这样既提高了系统的可靠性,同时也使得调试程序变得容易。

(2)在单片机系统中嵌入μC/OS-II将增加系统的开销。现在所使用的51单片机,一般是指87C51或者89C51,其片内都带有一定的RAM和ROM。对于一些简单的程序,如果采用传统的编程方法,已经不需要外扩存储器了。如果在其中嵌入μC/OS-II的话,在只需要使用任务调度、任务切换、信号量处理、延时或超时服务的情况下,也不需要外扩ROM了,但是外扩RAM是必须的。由于μC/OS-II是可裁减的操作系统,其所需要的RAM大小就取决于操作系统功能的多少。举例来说,μC/OS-II允许用户定义最大任务数。由于每建立一个任务,都要产生一个与之相对应的数据结构TCB,该数据结构要占用很大一部分内存空间。所以在定义最大任务数时,一定要考虑实际情况的需要。如果定得过大,势必会造成不必要的浪费。嵌入μC/OS-II以后,总的RAM需求可以由如下表达式得出:

RAM总需求=应用程序的RAM需求+内核数据区的RAM需求+(任务栈需求+最大中断嵌套栈需求)·任务数
所幸的是,μC/OS-II可以对每个任务分别定义堆栈空间的大小,开发人员可根据任务的实际需求来进行栈空间的分配。但在RAM容量有限的情况下,还是应该注意一下对大型数组、数据结构和函数的使用,别忘了,函数的形参也是要推入堆栈的。

(3)μC/OS-II的移植也是一件需要值得注意的工作。如果没有现成的移植实例的话,就必须自己来编写移植代码。虽然只需要改动两个文件,但仍需要对相应的微处理器比较熟悉才行,最好参照已有的移植实例。另外,即使有移植实例,在编程前最好也要阅读一下,因为里面牵扯到堆栈操作。在编写中断服务程序时,把寄存器推入堆栈的顺序必须与移植代码中的顺序相对应。

(4)和其他一些著名的嵌入式操作系统不同,μC/OS-II在单片机系统中的启动过程比较简单,不像有些操作系统那样,需要把内核编译成一个映像文件写入ROM中,上电复位后,再从ROM中把文件加载到RAM中去,然后再运行应用程序。μC/OS-II的内核是和应用程序放在一起编译成一个文件的,使用者只需要把这个文件转换成HEX格式,写入ROM中就可以了,上电后,会像普通的单片机程序一样运行。

结语

由以上介绍可以看出,μC/OS-II具有免费、使用简单、可靠性高、实时性好等优点,但也有移植困难、缺乏必要的技术支持等缺点,尤其不像商用嵌入式系统那样得到广泛使用和持续的研究更新。但开放性又使得开发人员可以自行裁减和添加所需的功能,在许多应用领域发挥着独特的作用。当然,是否在单片机系统中嵌入μC/OS-II应视所开发的项目而定,对于一些简单的、低成本的项目来说,就没必要使用嵌入式操作系统了。

围观 371

单片机应用系统中,常有用单片机的I/O口来实现自关机(彻底关机)的功能。一般用单片机的一个I/O口控制一个电子开关来实现,因单片机关电后,失去电源,所以在关机时,实现关机的IO口的电平必须用低电平。

但在这里有一个矛盾,就是在电子开关关闭电源时,因有电源滤波电容的存在,单片机系统的电压不是立即变为0,而是慢慢变低,当电压低到一定电压时,单片机 将进入复位状态、或程序跑飞状态、或不确定状态,此时单片机控制关电的I/O口也可能变回高电平,将使电子开关重新开通。

解决方法:

一般单片机最低工作电压要比正常工作的电压低一些,我们就用这个差别来设计关机电路,就是让电子开关的开通电压必须大于单片机的最低工作压,这样在单片机正常工作时,此控制电压较高,能维持电子开关的正常导通,而当单片机在关电过程中因低压而产生的I/O口的高电平,因电压较低,不足以维持电子开关的导通, 从而实现彻底的关电。

单片机如何通过I/O口实现断电自关机

在关机状态时:

S1按下,Q2导通,单片机工作后,POWER输出高电平,Q1导通,维持Q2的导通实现开机。

在开机状态时:

1、软件关机:MCU的POWER引脚输出低电平,Q1截止,Q2关断,关机。(一般用于延时关机,象数字万用表即是)

2、S1按下,低电平通过D3使MCU的输入脚ON-OFF电平为低,MCU检测到后,通过软件关机(如1所述)

D3用于隔离,不然关机状态时MCU的ON-OFF脚为低电平,Q2将导通。

POWER 是单片机输出开关电源的,低电平是0,高电平等于单片机的供电电压(近似)
ON-OFF是单片机的输入脚,用于单片机检测S1的状态,如果不用S1关机ON-OFF脚可以不用。

转自: 玩转单片机

围观 417

所谓“时序”从字面意义上来理解,一是“时间问题”,二是“顺序问题”。

先说“顺序问题”,这个相对简单一些。我们在学 UART 串口通信的时候,先 1 位起始位,再 8 位数据位,最后 1 位停止位,这个先后顺序不能错。我们在学 1602 液晶的时候,比如写指令,RS=L,R/W=L,D0~D7=指令码,这三者的顺序是无所谓的,但是最终的 E=高脉冲,必须是在这三条程序之后,这个顺序一旦错误,写的数据也可会出错。

“时间问题”内容相对复杂。比如 UART 通信,每一位的时间宽度是 1/baud。我们初中就学过一个概念,世界上没有绝对的准确。那么每一位的时间宽度 1/baud 要求精确到什么范围内呢?

前边教程我提到过,单片机读取 UART 的 RXD 引脚数据的时候,一位数据,单片机平均分成了 16 份,取其中的 7、8、9 三次读到的结果,这三次中有 2 次是高电平那这一位就是 1,有 2 次是低电平,那这一次就是 0。如果我们的波特率稍微有些偏差,只要累计下来到最后一位停止位,这 7、8、9 还在范围内即可。如图 13-1 所示。

简析单片机通信时序分析
图 13-1 UART 信号采集时序图

我们用三个箭头来表示 7、8、9 这三次的采集位置,大家可以注意到,当采集到 D7 的时候,已经有一次采集偏出去了,但是我们采集到的数据还是不会错,因为有 2 次采集正确。至于这个偏差允许多大,大家自己可以详细算一下。实际上 UART 通信的波特率是允许一定范围内误差存在的,但是不能过大,否则就会采集错误。大家在计算波特率的时候,发现没有整除,有小数部分的时候,就要特别小心了,因为小数部分是一概被舍掉的,于是计算误差就产生了。我们用 11.0592M 晶振计算的过程中,11059200/12/32/9600 得到的是一个整数,如果用 12M 晶振计算 12000000/12/32/9600 就会得到一个小数,大家可以算一下误差多少,是否在误差范围内。

1602 的时序问题,大家要学会通过 LCD1602 的数据手册提供的时序图和时序参数表格来进行研究,而且看懂时序图是学习单片机所必须掌握的一项技能,如图 13-2 所示。

简析单片机通信时序分析
图 13-2 1602 时序图

大家看到这种图的时候,不要感觉害怕。说句不过分的话,单片机这些逻辑上的问题,只要小学毕业就可以理解的,很多时候是因为大家把问题想象的太难才学不下去的。

我们先来看一下读操作时序的 RS 引脚和 R/W 引脚,这两个引脚先进行变化,因为是读操作,所以 R/W 引脚首先要置为高电平,而不管它原来是什么。读指令还是读数据,都是读操作,而且都有可能,所以 RS 引脚既有可能是置为高电平,也有可能是置为低电平,大家注意图上的画法。而 RS 和 R/W 变化了经过 Tsp1 这么长时间后,使能引脚 E 才能从低电平到高电平发生变化。

而使能引脚 E 拉高经过了 tD 这么长时间后,LCD1602 输出 DB 的数据就是有效数据了,我们就可以来读取 DB 的数据了。读完了之后,我们要先把使能 E 拉低,经过一段时间后 RS、R/W 和 DB 才可以变化继续为下一次读写做准备了。

而写操作时序和读操作时序的差别,就是写操作时序中,DB 的改变是由单片机来完成的,因此要放到使能引脚 E 的变化之前进行操作,其它区别大家可以自行对比一下。

细心的同学会发现,这个时序图上还有很多时间标签。比如 E 的上升时间 tR,下降时间时间 tF,使能引脚 E 从一个上升沿到下一个上升沿之间的长度周期 tC,使能 E 下降沿后,R/W 和 RS 变化时间间隔 tHD1 等等很多时间要求,这些要求怎么看呢?放心,只要是正规的数据手册,都会把这些时间要求给大家标记出来的。我们来看一下表 13-1。

简析单片机通信时序分析

大家要善于把手册中的这个表格和时序图结合起来看。表 13-1 中的数据,都是时序参数,本节课的所有时序参数,我都一点点的给大家讲出来,以后遇到同类时序图,就不再讲了,只是提一下,但是大家务必要学会自己看时序图,这个很重要,此外,看以下解释需要结合图 13-2 来看。

tC:指的是使能引脚 E 从本次上升沿到下次上升沿的最短时间是 400ns,而我们单片机因为速度较慢,一个机器周期就是 1us 多,而一条 C 语言指令肯定是一个或者几个机器周期的,所以这个条件完全满足。

tPW:指的是使能引脚 E 高电平的持续时间最短是 150ns,同样由于我们的单片机比较慢,这个条件也完全满足。

tR, tF:指的是使能引脚 E 的上升沿时间和下降沿时间,不能超过 25ns,别看这个数很小,其实这个时间限值是很宽裕的,我们实际用示波器测了一下开发板的这个引脚上升沿和下降沿时间大概是 10ns 到 15ns 之间,完全满足。

tSP1:指的是 RS 和 R/W 引脚使能后至少保持 30ns,使能引脚 E 才可以变成高电平,这个条件同样也完全满足。

tHD1:指的是使能引脚 E 变成低电平后,至少保持 10ns 之后,RS 和 R/W 才能进行变化,这个条件也完全满足。

tD:指的是使能引脚 E 变成高电平后,最多 100ns 后,1602 就把数据送出来了,那么我们就可以正常去读取状态或者数据了。

tHD2:指的是读操作过程中,使能引脚 E 变成低电平后,至少保持 20ns,DB 数据总线才可以进行变化,这个条件也完全满足。

tSP2:指的是 DB 数据总线准备好后,至少保持 40ns,使能引脚 E 才可以从低到高进行使能变化,这个条件也完全满足。

tHD2:指的是写操作过程中,要引脚 E 变成低电平后,至少保持 10ns,DB 数据总线才可以变化,这个条件也完全满足。

好了,表 13-1 这个 LCD1602 的时序参数表已经解析完成了,看完之后,是不是感觉比你想象的要简单,没有你想的那么困难。大家自己也得慢慢学会看这种时序图和表格,在今后的学习中,这方面的能力尤为重要。如果以后换用了其它型号的单片机,那么就根据单片机的执行速度来评估你的程序是否满足时序要求,整体上来说器件都是有一个最快速度的限制,而没有最慢限制,所以当换用高速的单片机后通常都是靠在各步骤间插入软件延时来满足较慢的时序要求。

转自: 畅学单片机

围观 410

页面

订阅 RSS - 单片机