标签存档: 单片机

为什么KeilC51下char型指针是3个字节

今天看到有位网友提问:


单片机中的sizeof的问题
是用KEILC51,单片机型号是AT89S52如下程序:char i,k,*p;i=6  ; p=&i; k=sizeof p;DEBUG观察K的值,是0x03请问这是为什么?32位机指针大小是4,那么8位的单片机就应该是1啊”

    在看到这个问题时我也不知道KeilC51下char型指针的长度到底是多少,但肯定不是1。因为如果是1,那寻址空间就只有256,而51单片机的外部数据存储器是可以扩展到地址0xFFFF的。所以,指针变量的长度至少是2字节。另外,这里还要注意,在一个系统中,指针变量的长度跟具体的变量类型是无关的。那么,在KeilC51中指针变量的长度到底是多少呢?是不是像网友说的3个字节呢?

继续阅读 »

KeilC在debug时查看RAM内容的方法

      在51单片机编程的过程中,在debug模式下怎样查看RAM的内容呢?在一般的IDE中,Memory窗口中就可以看到RAM空间的内容。但是在keil 51 中,在Memory窗口中输入址值,我们看到的是程序代码区的内容。
      由于51采用的是哈佛结构,程序存储和数据存储分开。要查看各种内存区域的内容,只要在Address框内输入“字母:地址”即可显示相应的内存值。其中字母可以是C、D、I、X,分别代表的意义是:

继续阅读 »

数学建模应当掌握的十类算法 转

数学建模应当掌握的十类算法
1、蒙特卡罗算法(该算法又称随机性模拟算法,是通过计算机仿真来解决问题的算
法,同时可以通过模拟可以来检验自己模型的正确性,是比赛时必用的方法)
2、数据拟合、参数估计、插值等数据处理算法(比赛中通常会遇到大量的数据需要
处理,而处理数据的关键就在于这些算法,通常使用Matlab作为工具)
3、线性规划、整数规划、多元规划、二次规划等规划类问题(建模竞赛大多数问题
属于最优化问题,很多时候这些问题可以用数学规划算法来描述,通常使用Lindo、
Lingo软件实现)
4、图论算法(这类算法可以分为很多种,包括最短路、网络流、二分图等算法,涉
及到图论的问题可以用这些方法解决,需要认真准备)
5、动态规划、回溯搜索、分治算法、分支定界等计算机算法(这些算法是算法设计
中比较常用的方法,很多场合可以用到竞赛中)
6、最优化理论的三大非经典算法:模拟退火法、神经网络、遗传算法(这些问题是
用来解决一些较困难的最优化问题的算法,对于有些问题非常有帮助,但是算法的实
现比较困难,需慎重使用)
7、网格算法和穷举法(网格算法和穷举法都是暴力搜索最优点的算法,在很多竞赛
题中有应用,当重点讨论模型本身而轻视算法的时候,可以使用这种暴力方案,最好
使用一些高级语言作为编程工具)
8、一些连续离散化方法(很多问题都是实际来的,数据可以是连续的,而计算机只
认的是离散的数据,因此将其离散化后进行差分代替微分、求和代替积分等思想是非
常重要的)
9、数值分析算法(如果在比赛中采用高级语言进行编程的话,那一些数值分析中常
用的算法比如方程组求解、矩阵运算、函数积分等算法就需要额外编写库函数进行调
用)
10、图象处理算法(赛题中有一类问题与图形有关,即使与图形无关,论文中也应该
要不乏图片的,这些图形如何展示以及如何处理就是需要解决的问题,通常使用Matlab
进行处理)

DS18B20时序问题的详细讨论

<p>今天弄DS18B20,发现按照DataSheet写的续写函数无法正常工作,估计是对DataSheet的理解不够。找来一个例程,仔细对比发现了差异。</p>
<p>详细分析如下:</p>
<p><a href="http://www.benp366.com/attachments/month_1006/z20106321721.png"><img title="image" border="0" alt="image" width="650" height="521" style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" src="http://www.benp366.com/attachments/month_1006/l20106321739.png" /></a></p>
<p><a href="http://www.benp366.com/attachments/month_1006/020106321753.png"><img title="image" border="0" alt="image" width="650" height="248" style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" src="http://www.benp366.com/attachments/month_1006/52010632189.png" /></a></p>
<h4>一、先看写时间片。</h4>
<h5>根据上面的说明:</h5>
<p>&nbsp;&nbsp;&nbsp; 写时间片在主机把数据线从高电平拉到低电平时开始。不论是写0还是写1都必须持续至少60us,写周期之间需要有1us的恢复间隔。</p>
<p>&nbsp;&nbsp;&nbsp; DS18B20在DQ线被拉低后的15us到60us内对DQ线进行采样。如果DQ线为高,则产生了一次写1操作,如果DQ线为0则产生了一次写0操作。</p>
<p>&nbsp;&nbsp;&nbsp; 主机要发出一个写1时间片,数据线必须拉低并且接着被释放(?这里的释放应该怎样理解?),以此来允许数据线在写时间片开始后的15us内上升到高电平。</p>
<p>&nbsp;&nbsp;&nbsp; 主机要发出一个写0时间片,数据线必须被拉低并且保持低电平60us。</p>
<p>根据以上说明和时序图,我写了如下的写字节函数。</p>
<h5>程序:</h5>
<p>sbit DQ=P1^7;</p>
<p>/*—————————————————————–*/</p>
<p>void delay(unsigned int i) <br />
{ <br />
&nbsp;&nbsp;&nbsp; while ((i–)!=1); <br />
}</p>
<p>/*—————————————————————–*/ <br />
void TmWrByte(unsigned char dat)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //读写都是从最低有效位开始 <br />
{ <br />
&nbsp;&nbsp;&nbsp; unsigned char k; <br />
&nbsp;&nbsp;&nbsp; for (k=1;k&lt;=8;k++) <br />
&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DQ=1; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DQ=0; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _nop_(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; _nop_(); <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DQ=dat&amp;0x01; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delay(6);&nbsp;&nbsp;&nbsp; //while( (i–)!=1 );&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 延时10*i个机器周期 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DQ = 1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //这里必须要拉高 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dat&gt;&gt;=1; <br />
&nbsp;&nbsp;&nbsp; }&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp; delay(5); <br />
}</p>
<h5>分析:</h5>
<p>DQ = 1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //这里必须要拉高&nbsp;&nbsp; ,我不明白为什么应该有这一条语句,但是没有这条语句就不能正常写操作。我猜想是一方面必须用拉高总线来结束写(一个位)操作,另一方面,完成一次写操作后需要释放总线。</p>
<p><span style="color: #ff0000">补充:通过查找资料,明白了这里DQ=1操作的含义。&ldquo;最后DQ又恢复为1,是总线的规范,在操作完后保证其为高电平,总线空闲时为高电平。如果不置为高电平,问题也不大,不过不操作时置高电平,是总线操作的习惯。&rdquo;</span></p>
<h3>二、再看读时序</h3>
<p><a href="http://www.benp366.com/attachments/month_1006/d20106321845.png"><img title="image" border="0" alt="image" width="650" height="221" style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" src="http://www.benp366.com/attachments/month_1006/e2010632199.png" /></a></p>
<h5>根据上面的说明:</h5>
<p>&nbsp;&nbsp;&nbsp; 当数据从DS18B20被读出来的时候主机开始读时间片。当主机把数据线从高拉到低时开始一个读时间片。数据线必须至少保持低电平1us;在读时间片的下降沿后的15us内DS18B20的输出数据都是有效的。同时,从读时间片开始后15us内主机必须停止驱动DQ脚为低从而来读取改线的状态。在读时间片结束时,DQ脚将会经由外部上拉电阻拉回到高电平。所有的读时间片必须持续至少60us,包含一个最短1us的读周期之间按的回复时间。</p>
<p>我写了如下程序:</p>
<p>/*—————————————————————–*/ <br />
unsigned char TmRdByte(void)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //读写都是从最低有效位开始 <br />
{ <br />
&nbsp;&nbsp;&nbsp; unsigned char k,v_byte=0; <br />
&nbsp;&nbsp;&nbsp; for(k=0;k&lt;8;k++) <br />
&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DQ=1; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DQ=0; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; v_byte=v_byte&gt;&gt;1; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; DQ=1;&nbsp;&nbsp;&nbsp; //必须像把I/O作为输入口使用一样先置1,再读取 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if (DQ) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; v_byte|=0x80; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; delay(6); <br />
&nbsp;&nbsp;&nbsp; } <br />
&nbsp;&nbsp;&nbsp; return(v_byte); <br />
}</p>
<h5>分析:</h5>
<p>这里在读取DQ之前(也就是if语句之前)还必须要DQ=1,我猜测,这是因为需要像把I/O作为输入口使用一样先置1,再读取。</p>
<p>关键就是这两个时序问题。</p>
<p>———————————————————————————————————-<br />
补充两个参考资料:</p>
<p>DS18B20 测温程序完全解读 <a href="http://bbs.21ic.com/viewthread.php?tid=44595&amp;highlight=DS18B20">http://bbs.21ic.com/viewthread.php?tid=44595&amp;highlight=DS18B20</a></p>
<p>&nbsp;振南的《单片机基础外设九日通》视频教程<u><font color="#0000ff"><a href="http://v.youku.com/v_playlist/f4243496o1p3.html">http://v.youku.com/v_playlist/f4243496o1p3.html</a></font></u></p>

MAX7219 串行8位LED数码管显示驱动芯片 总结

<p>一、小结:</p>
<p>1.对MAX7219的操作实际是对它的寄存器的操作。</p>
<blockquote>
<p>把寄存器的地址和该地址中应该存放的数据发送给MAX7219即可实现对7219的控制。8个数位寄存器用来存放每个数码管要显示的数据,6个控制寄存器用了存放控制命令。每次都应该发送16位的数据。数据格式如下:</p>
<p><a href="http://www.benp366.com/attachments/month_1006/f201061224451.png"><img title="image" border="0" alt="image" width="693" height="84" style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" src="http://www.benp366.com/attachments/month_1006/s201061224455.png" /></a></p>
<p>显然,高字节的第四位为寄存器地址,低字节为寄存器的内容。</p>
</blockquote>
<p>2.数据传输方式。</p>
<blockquote>
<p>单片机与7219之间的通信时通过DIN、LOAD、CLK三个接口实现的</p>
<p><a href="http://www.benp366.com/attachments/month_1006/q201061224523.png"><img title="image" border="0" alt="image" width="710" height="413" style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" src="http://www.benp366.com/attachments/month_1006/d201061224614.png" /></a></p>
<p>16-bit的串行数据包中的每一位(从高位到低位)在每个CLK的上升沿被移入16-bit的内部移位寄存器中,(对于7219而言此过程中LOAD可以为0也可以为1,但对于7221而言CS反必须为0)。接着,在LOAD的上升沿,这些数据被锁存(latched into)到数位寄存器(digit register)或控制寄存器(control register)。LOAD的上升沿必须在这16个CLK上升沿之后出现,并且要在下一个CKL之前,否则数据将会丢失。</p>
<p>寄存器地址表:</p>
<p><a href="http://www.benp366.com/attachments/month_1006/y201061224618.png"><img title="image" border="0" alt="image" width="335" height="393" style="border-bottom: 0px; border-left: 0px; display: inline; border-top: 0px; border-right: 0px" src="http://www.benp366.com/attachments/month_1006/h201061224629.png" /></a></p>
<div id="scid:0767317B-992E-4b12-91E0-4F059A8CECA8:8f968b32-08cc-43d4-b49a-62fcfeb726e7" class="wlWriterEditableSmartContent" style="padding-bottom: 0px; margin: 0px; padding-left: 0px; padding-right: 0px; display: inline; float: none; padding-top: 0px">奔跑 标签: <a rel="tag" href="http://www.benp366.com/%e5%8d%95%e7%89%87%e6%9c%ba+%e6%95%b0%e7%a0%81%e7%ae%a1+MAX7219">单片机 数码管 MAX7219</a></div>
<p>另外还有考虑译码模式,扫描范围,亮度设置等。我这里使用硬件八位全译码方式。</p>
</blockquote>
<p>3. 程序代码</p>
<blockquote>
<p>/****************************************************/ <br />
/*—————&nbsp;&nbsp; 7219相关的定义&nbsp;&nbsp;&nbsp; ————–*/ <br />
/****************************************************/ <br />
#define DecodeMode 0x09&nbsp;&nbsp;&nbsp;&nbsp; //译码模式 <br />
#define NoOp&nbsp;&nbsp; 0x00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //空操作寄存器 <br />
#define Intensity 0x0a&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //亮度 <br />
#define ScanLimit 0x0b&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //扫描界限 <br />
#define ShutDown 0x0c&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //掉电模式&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
#define DisplayTest 0x0f&nbsp;&nbsp;&nbsp; //显示测试</p>
<p>#define ShutdownMode 0x00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //掉电方式工作 <br />
#define NormalOperation 0x01&nbsp;&nbsp; //正常操作方式 <br />
#define DecodeDigit 0xff&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //硬件译码位数设置:高电平有效:0xff-硬件8位全译码:decode for digits 7-0 <br />
#define IntensityGrade 0x0f&nbsp;&nbsp;&nbsp; //显示亮度级别设置:16级 从0-15 <br />
#define ScanDigit 0x05&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //扫描位数设置:8位全扫描0X07,0x00-仅扫描第一位,现扫描6位 <br />
#define TestMode 0x01&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //显示测试模式:Display Test Mode <br />
#define TextEnd 0x00&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //显示测试结束,正常工作:Normal Operation</p>
</blockquote><blockquote>
<p>/***********************************************************************/ <br />
/***************&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; MAX7219&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ******************/ <br />
/***********************************************************************/ <br />
//gb 数据的串行送入,把一个字节从高位到低位按位送入7219。 <br />
//gb 7219工作方式:在LOAD状态(LOAD=0)下每个CLOCK的上升沿读入数据;并且在连续16个CLOCK上升沿以后,在数据丢失之前必须产生一个LOAD上升沿,在该上升沿数据会送入数码管和控制寄存器。</p>
<p>/*************第一块7219 的读写子程序***************/</p>
<p>/*———向7219送入一个字节———-*/ <br />
void SendChar1 (unsigned char ch)&nbsp;&nbsp;&nbsp; <br />
{ <br />
&nbsp;&nbsp;&nbsp; unsigned char i; <br />
&nbsp;&nbsp;&nbsp; _nop_(); <br />
&nbsp;&nbsp;&nbsp; for (i=0;i&lt;8;i++) <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; if(ch&amp;0x80)dis_DIN1=1; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; else&nbsp;&nbsp;&nbsp;&nbsp; dis_DIN1=0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dis_CLK=0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //上升沿送出 <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; dis_CLK=1; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; ch=ch&lt;&lt;1;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; <br />
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; } <br />
}</p>
<p>/*———-向7219写入操作码和操作数———-*/ <br />
void WriteWord1 (unsigned char addr,unsigned char num)&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; // 前8位是操作码(地址码),后8位是操作数 <br />
&nbsp;&nbsp; { <br />
&nbsp;&nbsp;&nbsp; dis_LOAD1=0;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp; //gb 在LOAD=0时允许读入数据 <br />
&nbsp;&nbsp;&nbsp; _nop_(); <br />
&nbsp;&nbsp;&nbsp; SendChar1 (addr); <br />
&nbsp;&nbsp;&nbsp; _nop_(); <br />
&nbsp;&nbsp;&nbsp; SendChar1 (num); <br />
&nbsp;&nbsp;&nbsp; _nop_(); <br />
&nbsp;&nbsp;&nbsp; dis_LOAD1=1;&nbsp; //锁存数据 <br />
&nbsp;&nbsp; }</p>
</blockquote>
<p>======================================================================</p>
<p>参考资料:</p>
<p>1. 内部逻辑结构</p>
<p>它主要由8个数位寄存器和6个控制寄存器组成:</p>
<p>1)数位寄存器7~0:它决定该位LED显示内容。</p>
<p>2)译码方式寄存器:它决定数位寄存器的译码方式,它的每一位对应一个数位。其中,1代表B码方式;0表示不译方式。若用于驱动LED数码管,应将数位寄存器设置为B码方式;当用于驱动条形图显示器时,应设置为不译码方式。</p>
<p>3)扫描位数寄存器:设置显示数据位的个数。该寄存器的D2~D0(低三位)指定要扫描的位数,支持0~7位,各数位均以1.3kHz的扫描频率被分路驱动。</p>
<p>4)亮度控制寄存器:该寄存器通常用于数字控制方式,利用其D3~D0位控制内部脉冲宽度调制DAC的占空比来控制LED段电流的平均值,实现LED的亮度控制。D3~D0取值可从0000~1111,对应电流占空比则从1/32变化到31/32,共16级,D3~D0的值越大,LED显示越亮。而亮度控制寄存器中的其他各位未使用,可置任意值。</p>
<p>5)显示测试寄存器:它用来检测外挂LED数码管各段的好坏。当D0置为1时,LED处于显示测试状态,所有8位LED的段被扫描点亮,电流占空比为31/32;若D0为0,则处于正常工作状态。D7~D1位未使用,可任意取值。</p>
<p>6)关断寄存器:用于关断所有显示器。当D0为0时,关断所有显示器,但不会消除各寄存器中保持的数据;当D0设置为1时,正常工作。剩下各位未使用,可取任意值。</p>
<p>7)无操作寄存器:它主要用于多MAX7219级联,允许数据通过而不对当前MAX7219产生影响。</p>
<p>2. 引脚说明</p>
<p>MAX7219是共阴极LED显示驱动器,采用24脚DIP和SO两种封装,其引脚排列见图1。其功能说明如下。</p>
<p>1)DIN:串行数据输入端。在CLK的上升沿,数据被装入到内部的16位移位寄存器中。</p>
<p>2)DIG7~DIG0:8位数值驱动线。输出位选信号,从每位LED显示器公共阴极吸入电流。</p>
<p>3)GND:接地端。</p>
<p>4)LOAD:装载数据控制端。在LOAD的上升沿,最后送入的16位串行数据被锁存到数据或控制寄存器中。</p>
<p>5)DOUT:串行数据输出端。进入DIN的数据在16.5个时钟后送到DOUT端,以便在级联时传送到下一片MAX7219。</p>
<p>6)SEG A~SEG G:LED七段显示器段驱动端。</p>
<p>7)SEG H:小数点驱动端。</p>
<p>8)Vcc:+5V电源端。</p>
<p>9)Iset:LED段峰值电流提供端。它通过一只电阻与电源相连,以便给LED段提供峰值电流。</p>
<p>10)CLK:串行时钟输入端。最高输入频率为10MHz,在CLK的上升沿,数据被移入内部移位寄存器;在CLK的下降沿,数据被移至DOUT端。</p>

单片机硬件系统设计原则

一个单片机应用系统的硬件电路设计包含两部分内容:一是系统扩展,即单片机内部的功能单元,如ROM、RAM、I/O、定时器/计数器、中断系统等不能满足应用系统的要求时,必须在片外进行扩展,选择适当的芯片,设计相应的电路。二是系统的配置,即按照系统功能要求配置外围设备,如键盘、显示器、打印机、A/D、D/A转换器等,要设计合适的接口电路。
  
  系统的扩展和配置应遵循以下原则:
  
  1、尽可能选择典型电路,并符合单片机常规用法。为硬件系统的标准化、模块化打下良好的基础。
  
  2、系统扩展与外围设备的配置水平应充分满足应用系统的功能要求,并留有适当余地,以便进行二次开发。
  
  3、硬件结构应结合应用软件方案一并考虑。硬件结构与软件方案会产生相互影响,考虑原则是:软件能实现的功能尽可能由软件实殃,以简化硬件结构。但必须注意,由软件实现的硬件功能,一般响应时间比硬件实现长,且占用CPU时间。
  
  4、系统中的相关器件要尽可能做到性能匹配。如选用CMOS芯片单片机构成低功耗系统时,系统中所有芯片都应尽可能选择低功耗产品。
  
  5、可靠性及抗干扰设计是硬件设计必不可少的一部分,它包括芯片、器件选择、去耦滤波、印刷电路板布线、通道隔离等。
  
  6、单片机外围电路较多时,必须考虑其驱动能力。驱动能力不足时,系统工作不可靠,可通过增设线驱动器增强驱动能力或减少芯片功耗来降低总线负载。
  
  7、尽量朝“单片”方向设计硬件系统。系统器件越多,器件之间相互干扰也越强,功耗也增大,也不可避免地降低了系统的稳定性。随着单片机片内集成的功能越来越强,真正的片上系统SoC已经可以实现,如ST公司新近推出的μPSD32××系列产品在一块芯片上集成了80C32核、大容量FLASH存储器、SRAM、A/D、I/O、两个串口、看门狗、上电复位电路等等。
单片机系统硬件抗干扰常用方法实践
  
   影响单片机系统可靠安全运行的主要因素主要来自系统内部和外部的各种电气干扰,并受系统结构设计、元器件选择、安装、制造工艺影响。这些都构成单片机系统的干扰因素,常会导致单片机系统运行失常,轻则影响产品质量和产量,重则会导致事故,造成重大经济损失。
  
  形成干扰的基本要素有三个:
  
  (1)干扰源。指产生干扰的元件、设备或信号,用数学语言描述如下:du/dt, di/dt大的地方就是干扰源。如:雷电、继电器、可控硅、电机、高频时钟等都可 能成为干扰源。
  
  (2)传播路径。指干扰从干扰源传播到敏感器件的通路或媒介。典型的干扰传 播路径是通过导线的传导和空间的辐射。
  
  (3)敏感器件。指容易被干扰的对象。如:A/D、D/A变换器,单片机,数字IC, 弱信号放大器等。
  
  干扰的分类
  
  1干扰的分类
  
  干扰的分类有好多种,通常可以按照噪声产生的原因、传导方式、波形特性等等进行不同的分类。按产生的原因分:
  
  可分为放电噪声音、高频振荡噪声、浪涌噪声。
  
  按传导方式分:可分为共模噪声和串模噪声。
  
  按波形分:可分为持续正弦波、脉冲电压、脉冲序列等等。
  
  2 干扰的耦合方式
  
  干扰源产生的干扰信号是通过一定的耦合通道才对测控系统产生作用的。因此,我有必要看看干扰源和被干扰对象之间的传递方式。干扰的耦合方式,无非是通过导线、空间、公共线等等,细分下来,主要有以下几种:
  
  (1)直接耦合:
  
  这是最直接的方式,也是系统中存在最普遍的一种方式。比如干扰信号通过电源线侵入系统。对于这种形式,最有效的方法就是加入去耦电路。从而很好的抑制。
(2)公共阻抗耦合:
  
  这也是常见的耦合方式,这种形式常常发生在两个电路电流有共同通路的情况。为了防止这种耦合,通常在电路设计上就要考虑。使干扰源和被干扰对象间没有公共阻抗。
  
  (3)电容耦合:
  
  又称电场耦合或静电耦合 。是由于分布电容的存在而产生的耦合。
  
  (4)电磁感应耦合:
  
  又称磁场耦合。是由于分布电磁感应而产生的耦合。
  
  (5)漏电耦合:
  
  这种耦合是纯电阻性的,在绝缘不好时就会发生。
  
  常用硬件抗干扰技术
  
  针对形成干扰的三要素,采取的抗干扰主要有以下手段。
  1 抑制干扰源
  抑制干扰源就是尽可能的减小干扰源的du/dt,di/dt。这是抗干扰设计中最优先考虑和最重要的原则,常常会起到事半功倍的效果。 减小干扰源的du/dt主要是通过在干扰源两端并联电容来实现。减小干扰源的di/dt则是在干扰源回路串联电感或电阻以及增加续流二极管来实现。
  抑制干扰源的常用措施如下:
  (1)继电器线圈增加续流二极管,消除断开线圈时产生的反电动势干扰。仅加 续流二极管会使继电器的断开时间滞后,增加稳压二极管后继电器在单位时间内可 动作更多的次数。
  (2)在继电器接点两端并接火花抑制电路(一般是RC串联电路,电阻一般选几K 到几十K,电容选0.01uF),减小电火花影响。
  (3)给电机加滤波电路,注意电容、电感引线要尽量短。 
  (4)电路板上每个IC要并接一个0.01μF~0.1μF高频电容,以减小IC对电源的 影响。注意高频电容的布线,连线应靠近电源端并尽量粗短,否则,等于增大了电 容的等效串联电阻,会影响滤波效果。
  (5)布线时避免90度折线,减少高频噪声发射。
  (6)可控硅两端并接RC抑制电路,减小可控硅产生的噪声(这个噪声严重时可能会把可控硅击穿的)。 
  2 切断干扰传播路径
  按干扰的传播路径可分为传导干扰和辐射干扰两类。
  所谓传导干扰是指通过导线传播到敏感器件的干扰。高频干扰噪声和有用信号的频带不同,可以通过在导线上增加滤波器的方法切断高频干扰噪声的传播,有时也可加隔离光耦来解决。电源噪声的危害最大,要特别注意处理。 
  所谓辐射干扰是指通过空间辐射传播到敏感器件的干扰。一般的解决方法是增加干扰源与敏感器件的距,用地线把它们隔离和在敏感器件上加 蔽罩。
  切断干扰传播路径的常用措施如下:
  (1)充分考虑电源对单片机的影响。电源做得好,整个电路的抗干扰就 解决了一大半。
  许多单片机对电源噪声很敏感,要给单片机电源加滤波电路或稳压器,以减小电源噪声对单片机的干扰。比如,可以利用磁珠和电容组成π形滤波电路,当然条件要求不高时也可用100Ω电阻代替磁珠。
  (2)如果单片机的I/O口用来控制电机等噪声器件,在I/O口与噪声源之间应加隔离(增加π形滤波电路)。
  (3)注意晶振布线。晶振与单片机引脚尽量靠近,用地线把时钟区隔离起来,晶振外壳接地并固定。
  (4)电路板合理分区,如强、弱信号,数字、模拟信号。尽可能把干扰源(如电机、继电器)与敏感元件(如单片机)远离。
  (5)用地线把数字区与模拟区隔离。数字地与模拟地要分离,最后在一点接于电源地。A
  /D、D/A芯片布线也以此为原则。
  (6)单片机和大功率器件的地线要单独接地,以减小相互干扰。 大功率器件尽可能放在电路板边缘。
  (7)在单片机I/O口、电源线、电路板连接线等关键地方使用抗干扰元件如磁珠、磁环、电源滤波器、屏蔽罩,可显著提高电路的抗干扰性能。
  3 提高敏感器件的抗干扰性能
  提高敏感器件的抗干扰性能是指从敏感器件这边考虑尽量减少对干扰噪声 的拾取,以及从不正常状态尽快恢复的方法。
  提高敏感器件抗干扰性能的常用措施如下:
  (1)布线时尽量减少回路环的面积,以降低感应噪声。
  (2)布线时,电源线和地线要尽量粗。除减小压降外,更重要的是降低耦 合噪声。 
  (3)对于单片机闲置的I/O口,不要悬空,要接地或接电源。其它IC的闲置端在不改变系统逻辑的情况下接地或接电源。  
  (4)对单片机使用电源监控及看门狗电路,如:IMP809,IMP706,IMP813, X5043,X5045等,可大幅度提高整个电路的抗干扰性能。
  (5)在速度能满足要求的前提下,尽量降低单片机的晶振和选用低速数字电路。
  (6)IC器件尽量直接焊在电路板上,少用IC座。
  4 其它常用抗干扰措施  
  交流端用电感电容滤波:去掉高频低频干扰脉冲。
  变压器双隔离措施:变压器初级输入端串接电容,初、次级线圈间屏蔽层与初级间电容中心接点接大地,次级外屏蔽层接印制板地,这是硬件抗干扰的关键手段。次级加低通滤波器:吸收变压器产生的浪涌电压。
  采用集成式直流稳压电源:因为有过流、过压、过热等保护。
  I/O口采用光电、磁电、继电器隔离,同时去掉公共地。
  通讯线用双绞线:排除平行互感。
  防雷电用光纤隔离最为有效。
  A/D转换用隔离放大器或采用现场转换:减少误差。
  外壳接大地:解决人身安全及防外界电磁场干扰。
  加复位电压检测电路。防止复位不充份,CPU就工作,尤其有EEPROM的器件,复位不充份会改变EEPROM的内容。
  印制板工艺抗干扰:
  ①电源线加粗,合理走线、接地,三总线分开以减少互感振荡。
  ②CPU、RAM、ROM等主芯片,VCC和GND之间接电解电容及瓷片电容,去掉高、低频干扰信号。
  ③独立系统结构,减少接插件与连线,提高可靠性,减少故障率。
  ④集成块与插座接触可靠,用双簧插座,最好集成块直接焊在印制板上,防止器件接触不良故障。
  ⑤有条件采用四层以上印制板,中间两层为电源及地