灞波儿奔

  • 2019-10-22
  • 发表了主题帖: PWM 和PFM

    PWM 和PFM 是两大类DC-DC 转换器架构 每种类型的性能特征是不一样的 重负载和轻负载时的效率 负载调节 设计复杂性 EMI / 噪声考虑 做电源设计的应该都知道PWM 和PFM 这两个概念 开关电源的控制技术主要有三种:(1)脉冲宽度调制(PWM);(2)脉冲频率调制(PFM);(3)脉冲宽度频率调制(PWM-PFM). PWM:(pulse width modulation)脉冲宽度调制 脉宽调制PWM是开关型稳压电源中的术语。这是按稳压的控制方式分类的,除了PWM型,还有PFM型和PWM、PFM混合型。脉宽宽度调制式(PWM)开关型稳压电路是在控制电路输出频率不变的情况下,通过电压反馈调整其占空比,从而达到稳定输出电压的目的。 PFM:(Pulse frequency modulation) 脉冲频率调制 一种脉冲调制技术,调制信号的频率随输入信号幅值而变化,其占空比不变。由于调制信号通常为频率变化的方波信号,因此,PFM也叫做方波FM PWM是频率的宽和窄的变化,PFM是频率的有和无的变化, PWM是利用波脉冲宽度控制输出,PFM是利用脉冲的有无控制输出. 其中PWM是目前应用在开关电源中最为广泛的一种控制方式,它的特点是噪音低、满负载时效率高且能工作在连续导电模式,现在市场上有多款性能好、价格低的PWM集成芯片;PFM具有静态功耗小的优点,但它没有限流的功能也不能工作于连续导电方式。 与PWM相比,PFM的输出电流小,但是因PFM控制的DC/DC变换器在达到设定电压以上时就会停止动作,所以消耗的电流就会变得很小。因此,消耗电流的减少可改进低负荷时的效率。PWM在低负荷时虽然效率较逊色,但是因其纹波电压小,且开关频率固定,所以噪声滤波器设计比较容易,消除噪声也较简单。   若需同时具备PFM与PWM的优点的话,可选择PWM/PFM切换控制式DC/DC变换器。此功能是在重负荷时由PWM控制,低负荷时自动切换到PFM控制,即在一款产品中同时具备PWM的优点与PFM的优点。在备有待机模式的系统中,采用PFM/PWM切换控制的产品能得到较高效率。

  • 2019-10-21
  • 发表了主题帖: 肖特基二极管用作与门或门的介绍

    肖特基二极管用作与门 如下图,n个肖特基二极管组成n输入的与门,只要A1~An中有一个信号输出逻辑0,则Output输出逻辑0,只有A1~An中所有信号输出逻辑1,Output才能输出逻辑1。即实现了信号A1~An的相与。由于在数字电路中,芯片信号输入级基本都是高阻的,因此,用肖特基二极管组成的与门电路总体电流都是ua级别的,肖特基二极管压降都是极其小的,电平仍能满足设计要求。 肖特基二极管用作或门 如下图,n个肖特基二极管组成n输入的或门,只要A1~An中有一个信号输出逻辑1,则Output输出逻辑1,只有A1~An中所有信号输出逻辑0,Output才能输出逻辑0。即实现了信号A1~An的相或。

  • 发表了主题帖: 小信号精密整流电路设计

    电路原理       交流小信号首先经过半波整流部分产生一半波信号,该信号再送入后级与输入信号进行叠加反向,输出的波形为全波整流信号。这个信号经一阶滤波电路后可得到较为平稳的直流信号。电路图中由 U1、D1、D2、R3、R2 构 成 半 波 整 流 部 分 ;由U2、R4、R6、R5 构成叠加反向部分;由 R1、C1 构成一阶滤波部分。电路中二极管导通电压为 0.6V左右,而集成运放的开怀放大倍数一般为万倍级,此时运放输入端仅需微伏级的净输入量就能使二极管导通。所以,运放输入端电压的微小变化,就能使输出跟随其发生变化。小信号精密整流电路        正是利用了这一特点,来实现对交流小信号的整流。电路中集成运放的型号主要根据输入信号的电压幅度及频率进行选择,此处选择OPA6951D,最大支持带宽可达500M。 半波整流 1.当输入交流小信号为电压正半周时: 因为 ui>0,所以 U1 的输出电压 uo1<0,使 D2 导通、D1截止。此时 R3、R2、U1 构成反向比例放大电路,其输出电压uo1=-(R2/R3)ui。电路中取 R3=R2,所以 uo1=-ui,电路为放大倍数为-1 的反向放大电路。 2.当输入交流小信号为电压负半周时: 因为 ui<0,所以 U1 的输出电压 uo1>0,使 D2 截止、D1导通。由于 D2 截止,使 U1 输出端的信号 uo1 不送入下一级(即 U2 的输入端);因为同向端接地,根据虚短原理,反向端电压为零,而此时 D1 导通,因此 U1 的输出电压 uo1 被钳位在 0V (即uo1=0) 。 叠加反向 根据原理图, R6、R4、R5 和 U2 共同构成反向加法电路,它将输入信号 ui 和 U1 的输出信号 uo1 进行反向叠加运算。uo2=-(R6/R4)uo1-(R6/R5)ui,因为 2R4≈R6、R6=R5,所以 uo2=-2uo1-ui。 当输入交流小信号为电压正半周时: ①因为 U1 输出的电压为 uo1=-ui,该信号经 U2 后输出为 uo2=2ui; ②该信号的输出为 uo2〞 =-ui; ③U2 的输出 uo2 =uo2 +uo2 〞 = ui。 即 当 输 入 为 正 半 周时,为等量同向输出。 当输入交流小信号为电压负半周时: ① uo1 被钳位在 0V,即 R3 左侧电压为0,而 R3 右侧电压根据虚短可知也为 0,所以理想情况下此时无电流流入 U2,即 uo2=0; ②该信号的输出为 uo2〞 =-ui; ③U2 的输出 uo2= uo2+ uo2〞 =-ui。即当输入为负半周 时,为等量反向输出。 总结:在整个周期内, U2 的输出为正半周电压加负半周的反向电压,从而实现了交流整流 

  • 发表了主题帖: 如何进行运放的参数和选择

    偏置电压和输入偏置电流     在精密电路设计中,偏置电压是一个关键因素。对于那些经常被忽视的参数,诸如随温度而变化的偏置电压漂移和电压噪声等,也必须测定。精确的放大器要求偏置电压的漂移小于200μV和输入电压噪声低于6nV/√Hz。随温度变化的偏置电压漂移要求小于1μV/℃ 。     低偏置电压的指标在高增益电路设计中很重要,因为偏置电压经过放大可能引起大电压输出,并会占据输出摆幅的一大部分。温度感应和张力测量电路便是利用精密放大器的应用实例。     低输入偏置电流有时是必需的。光接收系统中的放大器就必须具有低偏置电压和低输入偏置电流。比如光电二极管的暗电流电流为pA量级,所以放大器必须具有更小的输入偏置电流。CMOS和JFET输入放大器是目前可用的具有最小输入偏置电流的运算放大器。    因为我现在用的是光电池做采集的系统,所以在使用中重点关心了偏置电压和电流。如果还有其他的需要,这时应该对 其他参数也需要多考虑了。 1、输入失调电压VIO(Input Offset Voltage) 输入失调电压定义为集成运放输出端电压为零时,两个输入端之间所加的补偿电压。 输入失调电压实际上反映了运放内部的电路对称性,对称性越好,输入失调电压越小。输入失调电压是运放的一个十分重要的指标,特别是精密运放或是用于直流放大时。 2、输入失调电压的温漂αVIO(Input Offset Voltage Drift) 输入失调电压的温度漂移(又叫温度系数)定义为在给定的温度范围内,输入失调电压的变化与温度变化的比值。 这个参数实际是输入失调电压的补充,便于计算在给定的工作范围内,放大电路由于温度变化造成的漂移大小。一般运放的输入失调电压温漂在±10~20μV/℃之间,精密运放的输入失调电压温漂小于±1μV/℃。 3、输入偏置电流IB(Input Bias Current) 在使用运放中可能还会遇到一个输入偏置电流IB,输入偏置电流是指第一级放大器输入晶体管的基极直流电流。这个电流保证放大器工作在线性范围,为放大器提供直流工作点。 输入偏置电流定义为当运放的输出直流电压为零时,其两输入端的偏置电流平均值。 输入偏置电流对进行高阻信号放大、积分电路等对输入阻抗有要求的地方有较大的影响。输入偏置电流与制造工艺有一定关系,其中双极型工艺(即上述的标准硅工艺)的输入偏置电流在±10nA~1μA之间;采用场效应管做输入级的,输入偏置电流一般低于1nA。 对于双极性运放,该值离散性很大,但几乎不受温度影响;而对于MOS型运放,该值是栅极漏电流,值很小,但受温度影响较大。 4、输入失调电流(Input Offset Current) 输入失调电流 offset current,是指两个差分输入端偏置电流的误差。 输入失调电流定义为当运放的输出直流电压为零时,其两输入端偏置电流的差值。 输入失调电流同样反映了运放内部的电路对称性,对称性越好,输入失调电流越小。输入失调电流是运放的一个十分重要的指标,特别是精密运放或是用于直流放大时。输入失调电流大约是输入偏置电流的百分之一到十分之一。输入失调电流对于小信号精密放大或是直流放大有重要影响,特别是运放外部采用较大的电阻(例如10k或更大时),输入失调电流对精度的影响可能超过输入失调电压对精度的影响。输入失调电流越小,直流放大时中间零点偏移越小,越容易处理。所以对于精密运放是一个极为重要的指标。 5、输入阻抗 (1)差模输入阻抗 差模输入阻抗定义为,运放工作在线性区时,两输入端的电压变化量与对应的输入端电流变化量的比值。差模输入阻抗包括输入电阻和输入电容,在低频时仅指输入电阻。 (2)共模输入阻抗 共模输入阻抗定义为,运放工作在输入信号时(即运放两输入端输入同一个信号),共模输入电压的变化量与对应的 输入电流变化量之比。在低频情况下,它表现为共模电阻。 6、电压增益 (1)开环电压增益(Open-Loop Gain) 在不具负反馈情况下(开环路状况下),运算放大器的放大倍数称为开环增益,记作AVOL,有的datasheet上写成:Large Signal Voltage Gain。AVOL的理想值为无限大,一般约为数千倍至数万倍,其表示法有使用dB及V/mV等。 (2)闭环电压增益(Closed-Loop Gain) 顾名思义,就是在有反馈的情况下,运算放大器的放大倍数。 7、输出电压摆幅(Output Voltage Swing) 当运放工作于线性区时,在指定的负载下,运放在当前电源电压供电时,运放能够输出的最大电压幅度。 8、输入电压范围 (1)差模输入电压范围 最大差模输入电压定义为,运放两输入端允许加的最大输入电压差。 当运放两输入端允许加的输入电压差超过最大差模输入电压时,可能造成运放输入级损坏。 (2)共模输入电压范围(Common Mode Input Voltage Range) 最大共模输入电压定义为,当运放工作于线性区时,在运放的共模抑制比特性显著变坏时的共模输入电压。 一般定义为当共模抑制比下降6dB 是所对应的共模输入电压作为最大共模输入电压。最大共模输入电压限制了输入信号中的最大共模输入电压范围,在有干扰的情况下,需要在电路设计中注意这个问题。 9、共模抑制比(Common Mode Rejection Ratio) 共模抑制比定义为当运放工作于线性区时,运放差模增益与共模增益的比值。 共模抑制比是一个极为重要的指标,它能够抑制共模干扰信号。由于共模抑制比很大,大多数运放的共模抑制比一般在数万倍或更多,用数值直接表示不方便比较,所以一般采用分贝方式记录和比较。一般运放的共模抑制比在80~120dB之间。 10、电源电压抑制比(Supply Voltage Rejection Ratio) 电源电压抑制比定义为当运放工作于线性区时,运放输入失调电压随电源电压的变化比值。 电源电压抑制比反映了电源变化对运放输出的影响。所以用作直流信号处理或是小信号处理模拟放大时,运放的电源需要作认真细致的处理。当然,共模抑制比高的运放,能够补偿一部分电源电压抑制比,另外在使用双电源供电时,正负电源的电源电压抑制比可能不相同。 11、静态功耗 运放在给定电源电压下的静态功率,通常是无负载状态下。 这里就会有个静态电流 IQ的概念,静态电流其实就是指运放在空载工作时自身消耗的电流。这是运放消耗电流的最小值(排除休眠状态) 12、摆率(Slew Rate) 运放转换速率定义为,运放接成闭环条件下,将一个大信号(含阶跃信号)输入到运放的输入端,从运放的输出端测得运放的输出上升速率。 由于在转换期间,运放的输入级处于开关状态,所以运放的反馈回路不起作 用,也就是转换速率与闭环增益无关。转换速率对于大信号处理是一个很重要的指标,对于一般运放转换速率SR<=10V/μs,高速运放的转换速率 SR>10V/μs。目前的高速运放最高转换速率SR达到 6000V/μs。这用于大信号处理中运放选型。 13、增益带宽 (1)增益带宽积(Gain Bandwidth Product) 增益带宽积,GBP,带宽与增益的积。 (2)单位增益带宽 运算放大器放大倍数为1时的带宽。 单位增益带宽和带宽增益积这两个概念有些相似,但不同。这里需要说明的是对电压反馈型运放来说,增益带宽积是一个常数,而对于电流型运放来说却不是这样的,因为对于电流型运放而言,带宽和增益不是一个线性的关系。 14、输出阻抗 输出阻抗定义为,运放工作在线性区时,在运放的输出端加信号电压,这个电压变化量与对应的电流变化量的比值。在低频时仅指运放的输出电阻。这个参数在开环的状态下测试。 15、等效输入噪声电压(Equivalent Input Noise Voltage) 等效输入噪声电压定义为,屏蔽良好、无信号输入的的运放,在其输出端产生的任何交流无规则的干扰电压。 这个噪声电压折算到运放输入端时,就称为运放输入噪声电压(有时也用噪声电流表示)。对于宽带噪声,普通运放的输入噪声电压有效值约10~20μV。

  • 发表了主题帖: 运放的信号增益和噪声增益

         在我们平时的设计中很少用到噪声增益这个概念,因为它通常并不是多么的重要,忽略它对我们的设计也不会造成太大的影响,所以我们很少考虑它。但是有些时候我们常常在这个问题出错。下面就通过电路仔细分析一下噪声增益: 运放的信号增益和噪声增益       首先我们把两个开关都拨到上面的时候称为CASE1,都拨到下面的时候称为CASE2。这也就是我们平时所说的同相放大电路和反向放大电路。  在CASE1的情况下,信号增益为1+R1/R2,在CASE2的情况下,信号增益为-R1/R2,这两个电路的反馈是一样的,反馈系数都是R2/(R1+R2),所以他们的噪声增益都是(R1+R2)/R2。  而增益带宽积(这是用来简单衡量放大器的性能的一个参数。就像它的名字一样,这个参数表示增益和带宽的乘积。按照放大器的定义,对于一个运算放大器这个乘积是一定的)的表达式为GBP=Gn*B,所以两种情况下的带宽积是一样的。这里我们可以看出,这对反向放大器是很不利的。信号放大了R1/R2倍,带宽却减小了1+R1/R2倍。所以当我们在设计运放电路时,在增益带宽积的问题上只考虑电路的噪声增益就可以了,而与电路的放大模式无关。     分析模拟电路必须认识到:什么增益、稳定性、带宽之类,都是电路自身的内因,而输入信号一类的是外因。所以同相放大器和反相放大器其实是一个电路,两者的带宽其实应该完全一样,那一点点差异是别的原因。同相放大器和反相放大器归一,才有了所谓的噪声增益。     简单回顾运算放大器理论,可以看到有两种类型的增益与运算放大器有关:信号增益和噪声增益。信号增益取决于放大器配置。采用同相运算放大器配置时,增益计算公式为G = (RF /RG) + 1;采用反相配置时,增益为G = –RF/RG。两种配置的噪声增益相同,可通过同一个同相增益公式计算:NG = (RF /RG) + 1。电路中放大器的稳定性由噪声增益决定,而非信号增益。大多数现代运算放大器都能在单位增益下稳定,但某些特殊用途的放大器无法做到这一点。与标准单位增益稳定型运算放大器相比,非完全补偿运算放大器可提供独特的优势,比如更低的噪声电压和更宽的带宽。         强加噪声增益可为各种应用带来好处。例如,若要利用一种或多种特性,可能需采用低于其最小稳定增益的非完全补偿放大器。通常它将不起作用,但若对噪声增益进行处理,则可“欺骗”放大器,使其误以为它工作在较高的增益下。强加高噪声增益的另一个绝妙的好处是它可以提高放大器驱动容性负载时的稳定性。取决于具体情况,强加噪声增益通常需要在电路中加入一个电阻或一个电容。它可能简单到只需在反相和同相输入之间添加一个电阻、在反相输入和接地之间添加一个串联RC电路,或者将元器件与输入或增益电阻并联。强加噪声增益带来的好处似乎好得难以置信,但通常情况下它会牺牲一些性能。采用这种方法会造成输出噪声和失调电压的增加。但不可否认的是,说不定哪一天“强加”较高的噪声增益就派上了用场,成为运算放大器的又一种强大的技术特性。

  • 2019-10-16
  • 发表了主题帖: 单片机上电复位工作混乱的问题

         在单片机应用中经常需要在掉电时(包括人为的关机和偶然的外部电源故障),对运行的数据进行保存。目前,常用的方法是单独给单片机增加一个较大的电容(一般为2000 μf以上,也有用法拉级的),外部掉电后,靠大电容存储的电量缓慢放电,提供单片机向eeprom存储数据所需要的时间。所选的电容小,提供的时间短,存储数据不可靠,所选电容大提供时间长,存储数据可靠。但是随之而来的问题是,掉电后电容放电过程中,单片机的供电电压在缓慢下降,当下将到某个值但还没有降到复位门限电压之前,如果此时再次开机,则单片机不能正常启动,导致单片机重复上电后工作混乱。下面具体分析这一过程并给出解决的办法。   我们先了解一下AVR的上电复位特点。上表是AVR数据手册提供的上电复位参数。   AVR复位特征    ,即在单片机上电时,其电源电压要低于此值,才能使单片机上电复位。单片机的正常工作电源电压范围是2.7~5.5V。当电源电压低于2.7V时,单片机已经停止工作,如果此时电压高于1.3V,并且再次上电,则单片机不能正常复位,导致工作混乱。一些场合的停电可能是瞬间的,包括人为断电可能都是瞬间的,可能几秒钟之内又再次上电,而此时单片机电容的电压恰好处于复位电压以上和正常工作电压以下,就会出现上面的现象。这是本人在实际应用当中所遇到的情况。   由此可见,虽然解决了数据保护问题,却又带来了新的麻烦。所以在解决单片机掉电数据保护时,应该注意的是既要保证充足的时间用于数据存储,又要尽快放电,保证正常重新上电。     上图是本文所用的电路,图中交流电经过CON2输入,整流滤波后到达三端稳压块7806(注意在此用7806而不是7805),7806的输出一路经dl送到单片机(cpu_v=5.3V),单独给单片机供电,单片机耗电通常小于5毫安,由于使用C4(2200μf)电容,该路电源的放电时间较长。另外一路电源经过d2送到电路负载中(VCC=5.3V),通常此路电源的电流较大,超过几十毫安。   这样,在断电后,Vcc由于放电电流大而且滤波电容小,很快放电,通常在几毫秒以内。而另外一路cpu_v,由于滤波电容大而且放电电流小,所以放电很慢,t》2200μf×10-6×5V/5ma×10-3=2.2s;Vcc经过R4、W2分压接到单片机比较器的输入端ain0,cpu_v经过R6和稳压管(3.3V)接到单片机比较器的ain‘I端。电路正常工作时,调整电位器W2,使得ain0电压大于ain1电压0.2V,当掉电(或断电)发生时,ain0下降快,ainl下降慢,当ain0低于ainl时,比较器翻转。AVR比较器的翻转可以触发中断,在中断里完成eeprom的数据保存。图中Q1及周围的电路的工作作用是:初次上电时,由于电容C1两端电压不能突变,所以三极管的b、e结电压为OV,处于截止状态,截止的时间取决于Cl和R2的时间常数,本电路中参数可以保证截止时间超过10ms,在此时间之内CPU已经进入正常工作状态,在程序中将OUT端置“1”电平,继续使三极管截止。当断电发生时,先存储数据到eep-rom,然后out端置“0”电平,三极管饱和导通,立刻给cpu_v电源放电,R3是限流电阻。这样放电时间取决于R3和C4,大     

  • 发表了主题帖: 解决MCU启动异常的问题

             当对产品进行快速上下电测试时,若未能满足MCU的上下电要求,MCU往往会出现无法启动甚至锁死的问题。对于单电源供电的MCU来说,电路无需整改,本文推荐给您一颗LDO,可以解决MCU启动异常问题。   对于需要进行掉电保存或掉电报警功能的产品,利用大容量电容的储能作用,为保存数据和系统关闭提供时间,往往是很多工程师的选择。而在不需要掉电保存数据的系统中,为了抑制电源纹波、电源干扰和负载变化,在电源端也会并接一个适当容量的电容。   然而电路中电容并不是越大越好,由于电容的储能作用,大容量的电容则可能延长系统地上电时间和下电时间,而上下电时间的延长,则容易导致MCU启动失败或进入栓锁状态,因此缩短MCU电源的上电和放电时间就显得尤为重要。针对单电源的系统,ZLG推出了带EN控制和内嵌快速放电功能的LDO:ZL6205,来为您的系统助力。     图1 ZL6205   1.巧用EN,缩短上电时间   众所周知,满足MCU的上电时序,是系统设计最基本最重要的要求之一,因此仔细研读芯片的上下电时序是非常有必要的。如下图2所示为某系列MCU对上电时间的要求。      图2 上电要求   由上图可知该MCU对上电的主要要求有:   上电时间tr不能超过为500ms;   上电前的电压VI需要低于200mV至少12us。   这就要求尽可能地缩短上电时间,特别是电路中存在大电容或者超级电容时,上电时间过长容易导致系统无法启动或者器件闩锁的问题。   缩短上电时间,一种简单的方法莫过于控制电源芯片的EN引脚。巧用EN引脚的分压电阻就能够很好地缩短系统的上电时间。很多人在使用电源芯片时一般都是外部上拉来默认使能,而过早地达到使能阈值,输出就会跟随输入,即输入有多慢输出就有多慢,且上电时输入端的抖动也会传送给输出。如下图3所示为设置EN直接上拉和采用分压电路时的输出曲线示意图。     图3 EN上拉至输入和采用分压电路时的输出曲线   曲线①,使能上拉至输入,此时输出上升时间长且会受到输入波动的影响;   曲线②,合理采用分压电阻,当VIN上升到70%~80%的时候,再使EN的电压到达使能阈值,此时输出上升边沿陡峭,输出平稳,摒除了输入电源的不稳定阶段,减小了输入电压波动的影响。同时预留了20%~30%的余量,避免电源波动导致输出关闭。此时的上电对于MCU来说才是干净利落的!   说到这里就不得不说我司的自主芯片ZL6205了,采用SOT-23封装,带有EN使能引脚,可以灵活地控制输出电源,给后级电路一个干净、快速、稳定的电源。如下图4所示为ZL6205的典型应用图。      图4 ZL6205典型应用电路   解决了上电问题还不够?还有下电问题?别急,ZL6205还内嵌了快速放电电路,提升系统下电速度。   2.ZL6205自带放电电路,为快速下电助力   前面我们解决了上电缓慢的问题,并不意味着系统就能稳定地启动,由图2可知,还需要满足MCU上电时的输入电压低于200mV至少12us,这表明在快速上下电时,系统下电是否掉得“干净”和系统的启动也是息息相关的。    图5 掉电缓慢示意图   如图5所示,当系统掉电负载不能很快地泄放能量时,就会出现MCU等数字器件掉电缓慢的情况。若此时重新上电,由于芯片内部无法及时“归零”,对MCU等数字器件来说,这是一种不确定的状态,此时再对系统进行重新上电的操作,就容易造成MCU逻辑混乱,从而出现器件闩锁,系统不能启动的情况。   因此电源关闭后使MCU的电源快速下降至近0V,使系统在短时间内到达一种确定的状态,也是快速重新上电时系统能正常启动的关键因素。   下电缓慢的问题在设计过程中容易被忽略,在产品调试阶段才发现问题往往为时已晚,重新为系统增加快速放电电路既耗时又耗力。但若是系统中搭配了我司的ZL6205,掉电问题则可迎刃而解!     图6 ZL6205内部框图   如上图6所示为ZL6205的内部框图,当输入电压下电时,若EN电压低于使能阈值,则会启动内部的快速放电电路,在输出端加载一个240Ω的泄放电阻,以使输出电压迅速掉电。此时LDO的输出电压即MCU的输入电源,能够快速的“归零”,避免再次快速上电时系统启动失败。   3.解决方案推荐   当遇到系统启动失败的问题时,请先使用示波器检查器件的供电引脚是不是存在上电缓慢,掉电不彻底的情况。当遇到该情况时,可以选择在电路中搭配使用广州致远微电子有限公司自主研发的LDO:ZL6205。ZL6205是我司自行设计的一款500mA低压差线性稳压器,可在负载电流和电源电压变化时做出快速响应。   主要特性有:   500mA最大输出电流;   低压差(典型值为240mV@IO=500mA);   必要时外部10 nF旁路电容,用于低噪声;   快速启动;   具有快速放电功能;   静态电流典型值50μA;   初始电压精度±1.0%;   欠压保护;   过流保护;   短路保护;   过温保护;   选型表则如下表所示。   表1 ZL6205选型表   如何快速解决MCU启动异常的问题   注:其他输出电压可接受芯片定制。   4.结语   系统中的器件对于电源的上下电有严格的要求,在产品的设计当中,要关注核心器件的上下电要求,包括上下电的时序,斜率等。不合理的设计往往会引起系统上电无法启动等异常情况。

  • 发表了主题帖: 单片机中断优先级的设置方法解析

    包含五个中断源,两级中断优先级,优先级可编程设置,通过IP进行设置:   51单片机中断优先级的设置方法解析   PX0(IP.0),外部中断0优先级设定位;   PT0(IP.1),定时/计数器T0优先级设定位;   PX1(IP.2),外部中断0优先级设定位;   PT1(IP.3),定时/计数器T1优先级设定位;   PS (IP.4),串行口优先级设定位;   PT2 (IP.5) ,定时/计数器T2优先级设定位。     从这张图里我们可以看出:   EA是中断控制位,EA=1开放中断,EA=0屏蔽所用中断(编程时人为设定)   那EA是在哪里进行设置的呢?它就是在IE(中断允许寄存器)里进行设定的   第七位就是EA,剩下的还有第四位的ES,第三位的ET1,第二位的EX1,第一位的ET0和第零位的EX0,是不是在上图中都能看到他们的影子?没错,要不IE能称为中断允许寄存器嘛?是不是他先是设定总允许中断,然后再设定其它的中断是不是允许的,接下来我们再来看其它中断允许位   ES:串行口中断开放控制位,ES=1,响应串行口中断,ES=0,禁止串行口中断   ET1:T1溢出中断开放控制位,ET1=1,响应T1溢出产生的中断;ET1=0,禁止T1溢出产生的中断   EX1:外部中断1开放控制位,EX1=1,响应外部中断,EX1=0,禁止外部中断   ET0:功能同ET1,对应T0   EX0:功能同EX1,对应外部中断0   这样,中断是否开启就由你说了算了,你要用什么直接就可以控制对应的中断和总中断EA就可以了。   现在我们开启了中断,CPU就会检测对应的中断是否到来,那如何检测的呢?接下来我们就要用到另外几个有用的位了      TCON的第七位TF1,第五位TF0,第三位IE1,第一位IE0     SCON的第一位TI,第零位RI。   RI(SCON.0),串行口接收中断标志位。当允许串行口接收数据时,每接收完一个串行帧,由硬件置位RI。注意,RI必须由软件清除。   TI(SCON.1),串行口发送中断标志位。当CPU将一个发送数据写入串行口发送缓冲器时,就启动了发送过程。每发送完一个串行帧,由硬件置位TI。CPU响应中断时,不能自动清除TI,TI必须由软件清除。   TF1:T1当定时时间到或是当计数个数到的时候,会触发TF1位,然后CPU检测TF1位,执行对应的中断,响应中断后,硬件清零。   TF0:对应于TF1   IE1:外部中断请求标志,外部中断执行,请求中断,对应IE1=1,CPU响应中断,硬件对IE1清零。   IE0:对应IE1   但是对于外部中断,却有两种中断触发方式,一种是低电平触发,一种是下降沿触发。我们对于不同情况要进行不同的控制,那什么对这两种方式进行先择呢?我们看TCON的第二位和第零位是没有用的,就是他们两个,第二位IT1对应外部中断1,第零位IT0对应外部中断0,给他们高电平就为下降沿触发,给他们低电平就为低电平触发。

  • 2019-10-14
  • 发表了主题帖: MSP430F5438A的OV7670简单驱动程序

          首先简单的介绍一下所使用的摄像头OV7670。 OV7670是OV(OmniVision)公司生产的一颗1/6寸的CMOS VGA图像传感器。该传感器体积小、工作电压低,提供单片VGA摄像头和影像处理器的所有功能。通过SCCB 总线控制,可以输出整帧、子采样、取窗口等方式的各种分辨率8位影像数据。该产品VGA图像最高达到30帧/秒。用户可以完全控制图像质量、数据格式和传输方式。所有图像处理功能过程包括伽玛曲线、白平衡、度、色度等都可以通过SCCB接口编程。OmmiVision 图像传感器应用独有的传感器技术,通过减少或消除光学或电子缺陷如固定图案噪声、托尾、浮散等,提高图像质量,得到清晰的稳定的彩色图像。其具有高灵敏度、低电压适合嵌入式应用,标准的SCCB接口以及支持RGB565格式输出。因为摄像头的像素时钟非常高,直接通过MSP430的IO口读取数据非常困难,也是十分占耗CPU。采用带FIFO模块的OV7670,通过对FIFO的读取,就可以轻松的读取摄像头采集到图像数据。从而满足速度要求,节省CPU。本次采用的OV7670自带有源晶振,不需要外部再提供时钟。一个FIFO芯片的容量是384K字节,可以存储两帧QVGA的图像数据,所以本次设计采用QVGA模式  RGB565格式传输图像数据。接下来介绍具体的驱动程序。   宏定义: //SCL-P1.3,SDA-P1.6 #define SCCB_SIC_H()     P1OUT|=BIT3  #define SCCB_SIC_L()     P1OUT&=~BIT3     #define SCCB_SID_H()     P1OUT|=BIT6 #define SCCB_SID_L()     P1OUT&=~BIT6   #define SCCB_SID_IN      P1DIR &= ~BIT6     #define SCCB_SID_OUT     P1DIR |= BIT6    #define SCCB_SID_STATE     P1IN&BIT6   #define OE_L    P4OUT &= ~BIT3 #define OE_H    P4OUT |= BIT3 #define RCLK_L  P4OUT &= ~BIT4 #define RCLK_H  P4OUT |= BIT4 #define WEN_L   P4OUT &= ~BIT5 #define WEN_H   P4OUT |= BIT5 #define WRST_L  P4OUT &= ~BIT6 #define WRST_H  P4OUT |= BIT6 #define RRST_L  P4OUT &= ~BIT7 #define RRST_H  P4OUT |= BIT7   //像素存储 #define piexl_w 320 #define piexl_h 240 OV7670初始化程序: unsigned char ov7670_init(void) {     unsigned int i=0;   unsigned char temp;   //VSYNC-P1.0   //上拉输入,外部中断   P1DIR &= ~BIT0;   P1REN |= BIT0;   P1OUT |= BIT0;//上拉输入      //FIFO数据输入引脚   //D0-D3--P6.4-P6.7,D4-D7--P7.4--P7.7   //上拉输入   P6DIR &= 0x0f;   P6REN |= 0xf0;   P6OUT |= 0xf0;   P7DIR &= 0x0f;   P7REN |= 0xf0;   P7OUT |= 0xf0;      //OE-P4.3,RCLK-P4.4,WEN-P4.5,WRST-P4.6,RRST-P4.7   //输出   P4DIR |= 0xf8;   P4OUT |= 0xf8;   SCCB_init();            //读写寄存器函数出现错误     if(wr_Sensor_Reg(0x12,0x80)!= 0 ) //Reset SCCB     {           return 1;//错误返回     }                  delay_ms(50);              if(rd_Sensor_Reg(0x0b, &temp) != 0)//读ID     {         return 2 ;//错误返回     }                  if(temp==0x73)//OV7670      {        for(i=0;i<OV7670_REG_NUM;i++)        {         if(wr_Sensor_Reg(OV7670_reg[i][0],OV7670_reg[i][1]) != 0)         {                     return 3;//错误返回         }        }               }         return 0; //ok } 写寄存器操作函数如下:  //功能:读OV7660寄存器 //返回:0-成功    其他失败 unsigned char rd_Sensor_Reg(unsigned char regID,unsigned char *regDat) {     //通过写操作设置寄存器地址     startSCCB();     if(SCCBwriteByte(0x42)==0)//写地址     {                  return 1;//错误返回     }     delay_us(100);       if(SCCBwriteByte(regID)==0)//积存器ID     {                  return 2;//错误返回     }         delay_us(100);     stopSCCB();//发送SCCB 总线停止传输命令          delay_us(100);          //设置寄存器地址后,才是读     startSCCB();     if(SCCBwriteByte(0x43)==0)//读地址     {                  return 3;//错误返回     }     delay_us(100);       *regDat=SCCBreadByte();//返回读到的值       noAck();//发送NACK命令       stopSCCB();//发送SCCB 总线停止传输命令       return 0;//成功返回 }  读寄存器操作如下: //功能:读OV7660寄存器 //返回:0-成功    其他失败 unsigned char rd_Sensor_Reg(unsigned char regID,unsigned char *regDat) {     //通过写操作设置寄存器地址     startSCCB();     if(SCCBwriteByte(0x42)==0)//写地址     {                  return 1;//错误返回     }     delay_us(100);       if(SCCBwriteByte(regID)==0)//积存器ID     {                  return 2;//错误返回     }         delay_us(100);     stopSCCB();//发送SCCB 总线停止传输命令          delay_us(100);          //设置寄存器地址后,才是读     startSCCB();     if(SCCBwriteByte(0x43)==0)//读地址     {                  return 3;//错误返回     }     delay_us(100);       *regDat=SCCBreadByte();//返回读到的值       noAck();//发送NACK命令       stopSCCB();//发送SCCB 总线停止传输命令       return 0;//成功返回 } 简单的SCCB总线控制协议如下:   /* -----------------------------------------------    功能: 初始化SCCB端口,SCL-P1.3,输出,SCL-P1.3,输出    参数: 无  返回值: 无 ----------------------------------------------- */ void SCCB_init(void) {   //SDA-P1.6,上拉输入   P1DIR &= ~BIT6;   P1REN |= BIT6;   P1OUT |= BIT6;   //SCL-P1.3,输出   P1DIR |= BIT3;   P1OUT |= BIT3;      SCCB_SID_OUT; } /* -----------------------------------------------    功能: start命令,SCCB的起始信号    参数: 无  返回值: 无 ----------------------------------------------- */ void startSCCB(void) {     SCCB_SID_H();     //数据线高电平     SCCB_SIC_H();     //在时钟线高的时候数据线由高至低     delay_us(50);     SCCB_SID_L();     delay_us(50);     SCCB_SIC_L();     //时钟恢复低电平,单操作函数必要 } /* -----------------------------------------------    功能: stop命令,SCCB的停止信号    参数: 无  返回值: 无 ----------------------------------------------- */ void stopSCCB(void) {     SCCB_SID_L();     delay_us(50);     SCCB_SIC_H();         delay_us(50);     SCCB_SID_H();         delay_us(50); } /* -----------------------------------------------    功能: noAck,用于连续读取中的最后一个结束周期    参数: 无  返回值: 无 ----------------------------------------------- */ void noAck(void) {     delay_us(50);     SCCB_SID_H();         SCCB_SIC_H();         delay_us(50);     SCCB_SIC_L();         delay_us(50);     SCCB_SID_L();         delay_us(50); } /* -----------------------------------------------    功能: 写入一个字节的数据到SCCB    参数: 写入数据  返回值: 发送成功返回1,发送失败返回0 ----------------------------------------------- */ unsigned int SCCBwriteByte(unsigned int m_data) {     unsigned char j,tem;       for(j=0;j<8;j++) //循环8次发送数据     {         if(m_data&0x80)         {                     SCCB_SID_H();             }         else         {                     SCCB_SID_L();             }                 m_data<<=1;         delay_us(50);         SCCB_SIC_H();             delay_us(50);         SCCB_SIC_L();         }     SCCB_SID_IN;/*设置SDA为输入*/     delay_us(50);     SCCB_SIC_H();         delay_us(50);              if(SCCB_SID_STATE){tem=0;}   //SDA=1发送失败,返回0}     else {tem=1;}   //SDA=0发送成功,返回1     SCCB_SIC_L();                 SCCB_SID_OUT;/*设置SDA为输出*/       return tem;   } /* -----------------------------------------------    功能: 一个字节数据读取并且返回    参数: 无  返回值: 读取到的数据 ----------------------------------------------- */ unsigned char SCCBreadByte(void) {     unsigned char read,j;     read = 0x00;          SCCB_SID_IN;/*设置SDA为输入*/     for(j=8;j>0;j--) //循环8次接收数据     {                      delay_us(50);         SCCB_SIC_H();         read=read<<1;         if(SCCB_SID_STATE)          {                     read++;         }                 delay_us(50);         SCCB_SIC_L();              }             SCCB_SID_OUT;/*设置SDA为输出*/     return read; }           图像采集最重要的就是FIFO模块如何存储图像数据以及单片机如何读取FIFO模块中的图像数据。其具体的实现步骤如下: 摄像头模块存储图数据的过程为:等待OV7670同步信号、FIFO写指针复位、FIFO写使能、等待第二个OV7670同步信号、FIFO写禁止。         在存储完一帧图像以后,就可以开始读取图像数据了。读取过程为:FIFO读指针复位、给FIFO读时钟(FIFO_RCLK)、读取第一个像素高字节、给FIFO读时钟、读取第一个像素低字节、给FIFO读时钟、读取第二个像素高字节、循环读取剩余像素、结束。          因此使用一个外部中断(设计中为P1.0),来捕获帧同步信号,在中断服务函数中开始将OV7670的图像数据存储在FIFO芯片中。然后在一个帧同步信号到来之后,关闭数据存储。这样一帧数据就存储完成。中断服务函数源码如下: //FIFO模块存储摄像头数据 #pragma vector = PORT1_VECTOR __interrupt void PORT1_B0_ISR(void) {   if(P1IV == 2)   {       WRST_L;//开始复位写指针       WRST_H;//写指针复位结束       if(ov_sta == 0)        {         WEN_H;         ov_sta = 1;       }       else if(ov_sta == 1)        {         WEN_L;         ov_sta = 2;       }   }   P1IFG = 0;     //清除标志位 }       当FIFO芯片中一帧图像数据存储完毕就可以在主函数中进行430对FIFO芯片中数据的读取,特别注意,在读取FIFO芯片中的图像数据时,CS位要置低,否则输入管脚为高阻态。根据时序要求编写程序,源码如下:       /* OE  AL422 FIFO的输出使能引脚 ,OE为低电平时,允许数据输出 ,   高电平时,数据输出高阻态*/    OE_L; if(ov_sta == 2)//读数据       {         P1IE &= ~BIT0;//关外部中断         //设置图像分辨率         OV7670_Window_Set(180,10,piexl_w,piexl_h);                  RRST_L;//开始复位读指针         RCLK_L;         RCLK_H;         RCLK_L;         RRST_H;//读指针复位结束         RCLK_H;                 for(unsigned int p=0;p < piexl_h;p++)//传输图像piexl_w*piexl_h         {           for(unsigned int j=0;j < piexl_w;j++)           {             RCLK_L;             FIFO_1 = P6IN&0xf0;             FIFO_2 = P7IN&0xf0;             FIFO_data = (FIFO_1>>4)|FIFO_2;             data_fifo[0] = FIFO_data;//读取高字节             RCLK_H;               RCLK_L;             FIFO_1 = P6IN&0xf0;//读取低字节             FIFO_2 = P7IN&0xf0;             FIFO_data = (FIFO_1>>4)|FIFO_2;             data_fifo[1] = FIFO_data;             RCLK_H;            }           }         ov_sta = 0;         P1IE |= BIT0;      }         因为采用的是MSP430F5438a单片机,以QVGA模式传输图像数据还是很多,速度很慢。为降低传输的图像数据量,提高数据,借鉴了网上一个设置图像分辨率的函数,源码如下: //QVGA 分辨率设置 void OV7670_Window_Set(unsigned int sx,unsigned int sy,unsigned int width,unsigned int height) {     unsigned int endx;     unsigned int endy;     unsigned char temp;      endx=(sx+width*2)%784;    //   sx:HSTART endx:HSTOP          endy=sy+height*2;        //   sy:VSTRT endy:VSTOP                   rd_Sensor_Reg(0x32,&temp);        temp&=0Xc0;     temp|=((endx&0X07)<<3)|(sx&0X07);         wr_Sensor_Reg(0X032,temp);     wr_Sensor_Reg(0X17,sx>>3);                 wr_Sensor_Reg(0X18,endx>>3);                       rd_Sensor_Reg(0x03,&temp);        temp&=0Xf0;     temp|=((endy&0X03)<<2)|(sy&0X03);     wr_Sensor_Reg(0X03,temp);                     wr_Sensor_Reg(0X19,sy>>2);                 wr_Sensor_Reg(0X1A,endy>>2);             }    

  • 发表了主题帖: 深入理解C语言函数参数为指针

    我们直接做一个练习,定义一个函数,用来交换两个变量的内容。 void swap(int *x, int *y); void main(){     int x = 20, y = 10;     swap(&x, &y);     printf("x = %d, y = %d", x ,y); } void swap(int *x, int *y){     int t;     t = *x;     *x = *y;     *y = t; } 代码非常简单,我也就不细讲了。这里传入的参数为指针,所以调用 swap 方法后 x,y 的内容发生了交换。如果直接传入 x,y,那么交换只在 swap 中有效,在 main 中并没有交换。 4.2、函数的返回值为指针 返回值为指针的函数声明如下: 数据类型 *函数名(参数列表){     函数体 } //例如: int s; int *sum(int x, int y){     s = x + y;     return &s; } 在函数调用前要声明需要对函数声明(有点编译器不需要) int s; void mian(){     int *r = sum(10, 9);     printf("10 + 9 + %d", *r); } int *sum(int x, int y){     s = x + y;     return &s; } 除了上面的操作,更实用的是返回一个指向数组的指针,这样就实现了返回值为数组。 指向函数的指针 C 语言中,函数不能嵌套定义,也不能将函数作为参数传递。但是函数有个特性,即函数名为该函数的入口地址。我们可以定义一个指针指向该地址,将指针作为参数传递。 函数指针定义如下: 数据类型 (*函数指针名)(); 1 函数指针在进行“*”操作时,可以理解为执行该函数。函数指针不同与数据指针,不能进行+整数操作。 下面举个例子,来使用函数指针: #include <string.h> /** *    定义一个方法,传入两个字符串和一个函数指针 p,用 p 对两个字符串进行操作 */ void check(char *x, char *y, int (*p)()); void main(){     //string.h 库中的函数,使用之前需要声明该函数。字符串比较函数     int strcmp();     char x[] = "Zack";     char y[] = "Rudy";          //定义一个函数指针     int (*p)() = strcmp;     check(x, y, p); } void check(char *x, char *y, int (*p)()){     if(!(*p)(x, y)){         printf("相等");     }else{         printf("不相等");     } } 利用函数指针调用方法具体操作如下: (*p)(x, y); 1 指针除了这些地方,还在结构体中用处巨大。  

  • 发表了主题帖: 使用一根数据线控制全彩LED灯!单总线LED使用指南

    replyreload += ',' + 2911523;      相信大家学习单片机的第一课就是点亮第一盏LED灯了吧,初次点亮LED的时候的心情肯定是很激动的,可以操控眼前这个小小的芯片完成自己编写的指令,顿时感觉到很奇妙。初次了解之后便会激发我们的探索精神,当学习了PWM之后,控制RGB彩灯随意调出千变万化的颜色肯定不再是难事,用在各种项目上,RGB灯会让作品更加鲜艳动人。在这美丽的背后,其实隐藏了很多的科学道理,RGB灯的颜色能千变万化的原因是因为其内部集成了3个独立的3原色灯珠,然后使用PWM波控制每个灯珠处在不同的亮度,便可以得到不同的色彩。但是一个RGB灯可能会占用多个端口,想控制很多个RGB灯便是有些难度,好在随着集成工艺的发展,这一切不再是问题,如今的工艺促使了一种新型灯珠的出现,那就是单总线LED。        简单点来说就是这种类型的灯珠内置了一个驱动电路,它控制着灯珠发出的颜色,并且有一个数据输入口,意味着我们可以往在这个灯珠里面输入数据,然后灯珠内部的电路就会驱动的灯珠发出我们想要的颜色。这个电路呢还有一个数据的输出口,也就是说它可以将接受到的数据再次发送出去,送给下一个灯珠的输入,所以这使得所有的灯珠都可以连在一起,只需要使用一个IO口控制,这就相比传统的RGB灯节省了很多的端口。        这种类型的灯珠主要的核心就在它里面集成的那样一个驱动电路,这种类型的驱动电路有很多种,例如常见的WS2811,2812,SK6812等等,所以用其制作完成的灯珠一般都使用驱动电路的名字来命名。对于灯珠的大小型号呢,则有很多种类,例如5050,3535以及2020等封装,大家搜索的时候,搜索驱动电路的型号加上封装型号就可以找到想要的单总线LED了。下面是WS2812采用5050封装的图片。        本文会就WS2812这款最常用的驱动芯片来讲解其的控制方法以及在最后我会写一些控制这类单总线LED的方法。 由于是单总线通讯,自然没有时钟信号线,所以通讯的时序变得非常重要,我找到一份WS2812的数据手册,查看到了其中提到的输入数据时序图。      可以看到,2812芯片对着时序有着较为严格的需要,所以对于0码和1码,我们需要严格控制单片机延时的时间。并且这款芯片的时序大概都在纳秒级的延时,所以对于单片机的要求还是比较高的,我采用的是增强型的51单片机,速度上足够完成纳秒级的延时。       下面看到的数据的输入方法,可以看到每个数据包都是24bit长,也就是3个字节,发送完第一个24bit数据包之后就是接着发送第二个,可以看到在D2线上,第一个24bit数据包自动被忽略了,这是由于WS2812的转发机制,在其接受到第一个完整的24bit数据包之后,再接受到的数据包他会自动将其发送给下一个灯珠,这就是为什么可以一根线控制所有LED灯的秘密。并且WS2812芯片还有锁存的功能,也就是说送一次数据后,在下一回改变颜色之前都不需要再送数据了,内部的锁存电路会自动记住当前的颜色值,并控制灯珠一直保持着色彩。 对于每一个24bit数据包,其格式如下:每一个字节都表示着颜色的亮度,从高位到低位分别是绿色(G),红色(R),蓝色(B),控制这三个颜色的亮度,我们就可以得到千变万化的色彩。 了解到了数据包的格式,数据手册里面还给了一张应用电路的图片,很好的说明了这种单总线LED的连接方法。 看完了数据手册,下面就是对单片机编程,使其可以输出对应的波形了! 首先是对发送0码和1码的程序编写,由于需要用到纳秒级的延时,我使用空语句来进行软件延时,下面是发送0码和1码的代码截图。我这里是使用的STC15系列单片机,使用内部时钟11.0592MHZ,如果有使用相同单片机的朋友请直接参考我的代码,如果你的单片机类型不一样或者时钟频率不一样,最好使用示波器或者逻辑分析仪来得到精确的延时。 完成了发送0码和1码之后,接着就是发送一个字节了,核心思路就是每次判断字节高位的值来决定发送0还是1: 经过简单的编程,所有代码就完成了,简单的写了一个程序,让前三个灯亮起,呈红色: 其实WS2812的编程较为容易,下面就来说一些我的改进地方。 我编写了一个使用串口控制RGB灯的程序,就是我可以在串口上发送数据,实时的控制每个LED灯的颜色,这样会方便后期一些动画效果的控制。我定义了一个数据格式,一个数据包含有5个字节,分别是帧头,LED灯的编号,红色(R)亮度值,绿色(G)亮度值以及蓝色(B)亮度值。例如我想要控制第五个灯变成最亮的白色,我就发送 FFH 05H FFH FFH FFH 就可以了 其思路就是当串口收到帧头之后,就开始读取灯的编号以及各个颜色的亮度值,然后再发送给LED灯珠即可。最后我会附上我的代码,供大家下载。       游客,如果您要查看本帖隐藏内容请回复

  • 2019-10-13
  • 发表了主题帖: 简易单片机计算器的proteus仿真实现

    一个简单的加减乘除计算器/*注意上面头文件"bsp_GOG1.h"包含一个可选宏定义           若需使用扩展板请增加全局宏定义 _GOG1Plus         定义方式          菜单 Project->Options for Target->C51->Define         在此处填入   “_GOG1Plus” 在此代码完全兼容,第三次课的矩阵按键程序,在此感谢魏同学的帮助 */ /* 计算器功能实现:4位数字的加,减,乘法,除法没有做商的小数部分 1.对输入运算数的有效性检查,即超过9999时,显示错误; 2,用LED--》D3来指示系统的正常运行状态 3,运算的结果超过9999时,提示错误显示; 4,当系统运行错误时,或者显示乱码时,按A键清除数码管显示; 5,除法运算时,的二个运算数为0时,提示错误显示 6, 运算表达式不完整时,报错:                       (1)无数 * 第二个数 = 报错                       (2)第一个数 * 无数 = 报错                       (3)直接按等号,报错 7,D3 LED灯实际是隔1ms 闪烁一次, */ /*矩阵按键 功能定义:  #define ADD        15          //'#':加法  S15 #define SUB        12          //'C':减法  S12 #define MUL        14          //'*':乘法  S13 #define DIV        11          //'B':除法  S8 #define EQU        13          //'D':等于  S16 #define CLE     10        //'A':清除  S4 仿真图:   单片机源程序如下: #include <REG52.H>          //51单片机标准寄存器声明头文件 #include "bsp_GOG1.h"   //这个头文件用于映射GOG1学习板载硬件接口 /*计算器的运算状态定义:*/ #define NoKey       0xaa  //没有按键按下的状态 #define ErrKey      0xff  //错误的按键状态/干扰 #define DpyErr            0x0e  //错误显示状态(码表数组第14个元素:'E') #define DpyCle      0x10  //清屏(码表数组第16个元素:0xff 关闭数码管) #define InCount         0xf0  //有运算符输入状态 #define InErrEqu          0x0f  //有等号输入状态 #define NoCountFlag 0xa5  //没有运算符的状态 /*矩阵按键 功能定义: */ #define ADD        15          //'#':加法  S15 #define SUB        12          //'C':减法  S12 #define MUL        14          //'*':乘法  S13 #define DIV        11          //'B':除法  S8 #define EQU        13          //'D':等于  S16 #define CLE 10    //'A':清除  S4 /*相关子函数的声明:*/ void delayms(unsigned int ms);                          //延时函数 void SegDisplay(unsigned char casebit);         //数码管显示函数 unsigned char ReadKeyPad(void);          //读取矩阵键盘函数 void Timer0Init(void);                                         //定时器0初始化函数 unsigned char CheckInput(void);                         //计算器检查输入状态函数 void DatUnpack(unsigned int dat);                 //计算器数据拆分函数 bit CheckNum(unsigned int dat);                         //计算器数据有效性检查函数 void WarmDpy(unsigned char err);                 //计算器错误显示函数 void ComputeState(unsigned char dat);         //计算器计算过程函数   //数码管段码表 共阳  17个元素: 0~F & 0xff unsigned char code SegCode[17]= {0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,                                  0x90,0x88,0x83,0xc6,0xa1,0x86,0x8e,0xff}; unsigned int Ans;              //运算结果   bit AnsFlag=0;            //运算结果存在标志 bit InFlag1=0;                      //输入有效数字1标志 bit InFlag2=0;                      //输入有效数字2标志 unsigned char CountFlag;  //运算符 unsigned int  temp1=0,temp2=0;//输入的2个运算的数字 unsigned char DisBuff[4]={DpyCle,DpyCle,DpyCle,DpyCle};//数码管显示缓存 /*******************************************************************************   * @brief  mian           (简介)   * @param  无                   (参数)   * @retval 无                   (返回值)   ******************************************************************************/ void main(void)                                    //程序从这里开始 {     unsigned char in;                        //保存单个按键值的变量          CountFlag=NoCountFlag;                //运算符初始状态     Timer0Init();                                //定时器0初始化     while(1)     {         in=CheckInput();         while(in == NoKey) in=CheckInput(); //没有按键按下,在此等待         if(in !=ErrKey)                //按键有效         {           ComputeState(in);           }           else  WarmDpy(DpyErr); //按键无效,报错 'E'       } } /*******************************************************************************   * @brief  ComputeState: 计算过程程序   * @param  unsigned char dat   * @retval 无 *******************************************************************************/   void ComputeState(unsigned char dat) {     unsigned int num;         //保存运算操作数的变量     if(AnsFlag == 1)     //判断上一次运算结果完成标志     {         WarmDpy(DpyCle); //清屏         AnsFlag=0;                 //清除有效运算完成标志     }     if((dat !=InCount)&(dat !=InErrEqu)&(dat <10)) //按下的键为数字     {           if(CountFlag == NoCountFlag) //没有运算符存在,保存第一个数         {             num = temp1;             num *= 10;                                 //输入的数字依次进高位             num += dat;             if( CheckNum(num)==1 )   //判断数据有效性             {                                             //有效在数字范围                 temp1 = num;                  //保存第一个数字                 InFlag1 = 1;         //输入有效数字1标志                 DatUnpack(temp1);    //拆分数据,更新显示缓存             }             else WarmDpy(DpyErr);    //超出范围报错         }         else              //运算符存在 ,保存第二个数         {             num = temp2;             num *= 10;             num += dat;             if(CheckNum(num)==1)             {                 temp2 = num;                 InFlag2 = 1;     //输入有效数字2标志                 WarmDpy(DpyCle); //清除第一个数的显示,消除'余晖'                 DatUnpack(temp2);//更新显示缓存             }             else WarmDpy(DpyErr);         }     }     else    //按下的键为非数字(4则运算符被保存,这里考虑 清除键和 错误等号)     {         if(CLE == dat)                 //按下的为清除键         {             CountFlag = NoCountFlag; //清除运算符             InFlag1 =0;                                 //清除输入有效数字1标志             InFlag2 =0;              //清除输入有效数字2标志             AnsFlag=0;                                 //清除运算结果存在标志             temp1=0,temp2=0;         //清除输入的2个运算数             WarmDpy(DpyCle);                 //清屏             Ans=0;                                         //清除上一次运算结果                  }                  if(InErrEqu == dat)                            //运算表达式不完整时,按下等号的情况             WarmDpy(DpyErr);         //报错 'E'     } }   /*******************************************************************************   * @brief  ReadKeyPad        用于读取矩阵键盘键值   * @param  无   * @retval 矩阵键盘键值   * @note   键盘键值设置请修改case分支临时变量b的赋值                                                 0xff 作为错误代码,表示读取出错 ******************************************************************************/ unsigned char ReadKeyPad(void) {     unsigned char a,c,b=NoKey; //b 初始值为无按键的状态     KeyPad = 0x0f;    //初始状态,行号(P3^0~P3^3)高电平,列号(P3^4~P3^7)低电平     if(KeyPad != 0x0f)     {         delayms(20);                 //按键消抖动(延时实现)         if(KeyPad != 0x0f)         //按键被按下,初始状态改变         {             a = KeyPad;                 //读取矩阵键盘的行号         }         KeyPad = 0xf0;                 //初始状态反转         c = KeyPad;                         //读取矩阵键盘的列号         a |= c;                                 //按位'或',通过行号,列号唯一确定矩阵按键值         switch (a) {         case 0xee:             b = 1;                          //S1             break;         case 0xed:             b = 4;                          //S5             break;         case 0xeb:             b = 7;                          //S9             break;         case 0xe7:             b = MUL;                  //S13'MUL'             break;         case 0xde:             b = 2;                          //S2             break;         case 0xdd:             b = 5;                          //S6             break;         case 0xdb:             b = 8;                          //S10             break;         case 0xd7:             b = 0;                          //S14             break;         case 0xbe:             b = 3;                         //S3             break;         case 0xbd:             b = 6;                         //S7             break;         case 0xbb:             b = 9;                         //S11             break;         case 0xb7:             b = ADD;                 //S15 'ADD'             break;         case 0x7e:             b = CLE;                 //S4 'CLE'             break;         case 0x7d:             b = DIV;                 //S8 'DIV'             break;         case 0x7b:             b = SUB;                 //S12 'SUB'             break;         case 0x77:             b = EQU;                 //S16 '='             break;         default :                         //没有和 a 的匹配项             b = ErrKey;                 //错误的按键值             break;         }         KeyPad = 0xf0;                        //松手检测         while (KeyPad != 0xf0);        //当没有松手,将在此一直等待     }     return (b);                                //返回读取的按键值 }   /******************************************************************************   * @brief  delayms        毫秒级延时函数   * @param  ms        延时的毫秒数 允许值 unsigned int范围   * @retval 无   * @attention   这个函数只是用于12T 8051内核的单片机运行于12Mhz   *****************************************************************************/ void delayms(unsigned int ms)         //延时子程序(晶振12Mhz) {     unsigned char i;     while(ms--)     {         for(i = 0; i < 120; i++);     } }   /******************************************************************************   * @brief  SegDisplay 数码管显示&定时器中断程序组成动态显示   * @param  casebit        用于选择数码管的位 允许值 0~4   * @retval 无   * @attention   这个函数需配合定时器中断服务程序   *****************************************************************************/ void SegDisplay(unsigned char casebit) {     Seg7_Bits = 0xff;                             //关闭所有数码管     Seg7_Data =SegCode[DisBuff[casebit]];//先把段码值赋给P1(段选端口)     switch(casebit)     {     case 0:         Seg7_Bit1 = 0;         break;     case 1:         Seg7_Bit2 = 0;         break;     case 2:         Seg7_Bit3 = 0;         break;     case 3:         Seg7_Bit4 = 0;         break;     default :         Seg7_Bits = 0xff;        //关闭所有数码管         Seg7_Data = 0xff;         break;     } } /************************************************************************************   * @brief  DatUnpack:数据拆分,同时把数据的千位,百位,十位,个位赋给显示缓存数组DisBuff[]   * @param  unsigned int dat   * @retval 无   ***********************************************************************************/ void DatUnpack(unsigned int dat) {       if((dat<10))                                     //1位数         DisBuff[0]=dat;     else if((dat<100)&&(dat>=10))         //2位数     {         DisBuff[1]=dat/10;         DisBuff[0]=dat%10;     }     else if((dat<1000)&&(dat>=100))         //3位数     {         DisBuff[2]=dat/100;         DisBuff[1]=dat%100/10;         DisBuff[0]=dat%100%10;     }     else if ((dat<10000)&&(dat>=1000))//4位数     {         DisBuff[3]=dat/1000;         DisBuff[2]=dat%1000/100;         DisBuff[1]=dat%1000%100/10;         DisBuff[0]=dat%1000%100%10;     }   } /*******************************************************************************   * @brief  unsigned char CheckInput(): 检查矩阵键盘输入按键的类型(简介)   * @param  无                                                                                                          (参数)   * @retval  数字,功能键(CLE,EQU,+,-,*,/),无按键的状态                          (返回值)   ******************************************************************************/ unsigned char CheckInput(void) {     unsigned char x;     x=ReadKeyPad();         //调用读按键子程序     if(x != ErrKey)         //是否为错误按键值     {         if((x<10)|(x == NoKey)| (x == CLE))//按下的为数字,或没有按键按下,或清除键         {             return (x);         }         else           //按下的为 运算符(四则运算 和 等号)         {             if(x == EQU) // 按下的为 等号"="             {                                                                      switch (CountFlag)                 {                 case ADD:         Ans = temp1+temp2; break;                 case SUB:         Ans = temp1-temp2; break;                 case MUL:         Ans = temp1*temp2; break;                 case DIV:   if (temp2 == 0) //除法分母为0,报错                     {                         WarmDpy(DpyErr);                         break;                     }                     else                     {                         Ans = temp1/temp2;//只计算除法商的整数,暂没有考虑小数                         break;                     }                 }                 if( CheckNum(Ans)&&(InFlag1 ==1)&&(InFlag2 ==1))//检测运算的有效性                                   {                            DatUnpack(Ans);                //运算结果拆分,更新显示缓存                     CountFlag = NoCountFlag;        //清除运算符                     temp1=0,temp2=0;                        //清除运算数字                     AnsFlag = 1;                                //运算结果存在标志                     InFlag1 =0;                                //清除有效数字输入标志                     InFlag2 =0;                     Ans=0;                                        //清除运算结果                     return (NoKey);                        //此次运算完成,返回无按键状态                   }                  else //WarmDpy(DpyErr) ;//运算表达式不完整或结果超出范围,报错                     return (InErrEqu);                 //返回有等号输入的状态                     }             else  //按下的为 4则 运算符(+ ,-,*, /)             {                 CountFlag = x;                 //保存运算符                 return (InCount);                 //返回有运算符输入的状态             }           }     }     else  return (ErrKey);                //返回错误按键值状态 } /*******************************************************************************   * @brief  CheckNum: 检查计算器运算数的有效性   * @param  dat   * @retval bit 有效: 1,无效: 0   ******************************************************************************/ bit CheckNum(unsigned int dat) {     if (dat < 10000)         return 1;          //数据有效     else         return 0;   } /*******************************************************************************   * @brief  WarmDpy:数码管错误显示    * @param  err                实则:'E'的码段值元素的下标   * @retval 无   ******************************************************************************/ ……………………

  • 发表了主题帖: 油站油气回收自动监测系统中的流量原理介绍

    本帖最后由 灞波儿奔 于 2019-10-13 21:03 编辑          说起油气回收改造工作,人们首先想到的是加油站油气回收改造,油库和加油站均已安装了一级、二级油气回收系统。近期,在此基础上,对一级、二级油气回收系统再升级。            中石化第十二站加油站开始对加油站进行了升级改造,增加总价30余万元的油气在线监测设备,通过增设油气流量传感器、压力传感器等,可采集油气流量计和压力传感器的数据,同时采集加油量脉冲信号,能实时监测加油站油气回收系统,并将数据分类存储。        同时,在加油站内设立在线监测的实时数据显示屏,油罐压力、管道压力、油气浓度等数据都能在后台看得一清二楚,一旦监测到设备出现故障或数据不正常的情况,就能自动保存数据并产生报警信息和声光报警提示,还具有关闭气液比不合格加油枪的功能,有效降低了油气排放的环保风险。接下来,该数据还将实时传送到环保部门,为环保部门提供环境监测的数据分析。下面工采网小编便为大家介绍一下流量传感器在加油站油气回收自动监测系统中的应用。        加油站的油气回收系统进行再升级,通过最新安装的油气回收自动监测系统,借助油气流量传感器、压力传感器等传感器监设备,有效实现了油气回收情况实时在线监测。在加油站油气回收自动监测系统中,传感器主要是指安装在加油站各管路上的现场仪表,包括压力传感器、气体流量传感器、浓度检测仪等。      回顾流量计在油田中的应用工采网小编曾写过《油气田中气体流量传感器的应用》、《矽翔气体质量流量计在石油化工行业中的应用》、《自动化设备中关于流量测量的相关技术解决方案》等文章。其中在《自动化设备中关于流量测量的相关技术解决方案》一文中便提及了流量计在油田自动化计量系统中的应用详情可点击文章链接查看。接下来我们继续了解油气回收自动监测系统及其中的传感器技术。       加油站的油气,主要是指在加油过程中外溢的气态汽油,它将引起一系列的环境问题。比如:加油站的油气挥发物被吸入人体后,还会对人体产生直接危害;油气挥发物经紫外线照射后,会与空气中的氮氧化物发生化学反应,生成光化学烟雾,影响空气质量。而有时候,油气回收系统出现问题,加油站并不知情,要解决这些问题,最好的办法就是上线油气回收自动在线监测系统。      油气回收,是指汽油储运、销售过程中所产生的油气通过一定装置进行回收,将油罐车卸油、加油机加油过程中挥发的油气收集到地下储油罐内,因此,开展油气回收及长效监管是削减VOCs排放量,进一步改善环境空气质量的一种有效措施。      而油气回收自动监测系统,是指油气回收在线监测系统是在油气回收系统的基础上,对油气回收运行参数进行在线监测的一系列设备的组合。            一般来说,油气回收自动监测系统由传感器、电测子系统、数据远程传输系统、数据集中管理软件平台组成。因实际应用技术不同,系统的组成也不一样。比如,气体流量计安装于加油机内气路上,用于监测每次加油操作的回气体积;压力传感器安装于与地下储油罐直接连通的气路上,如加油机底部回气总管处或后处理装置进气口处。数据采集器位于加油机内,用于采集加油脉冲、回气脉冲和压力信号,并通过通信线缆将数据传入监控机进行处理。      但就目前市场而言在传感器实际应用中,中石化、中石油及一些民营油站采用的油气回收在线监测系统能够,采用的多是国外传感器设备,那是因为这些传感器均有使用寿命长、结构紧凑、安装方便的特点,例如VFS气体流量传感器,美国维德路特Veeder-Root公司的罗茨流量计和压力传感器,以及德国法夫尼尔FAFNIR公司的油气传感器等。除了上述提及的国外传感器外工采网在流量传感器方面也有多款产品可以应用在不同领域例如:美国Siargo 气体质量流量传感器 - FS4001适用于小流量气体质量的流量测量;气体质量流量传感器 - FS4000系列适用于净化空气或氮气流量监控,还可用于环境采样器(如色谱分析仪器等);Siargo矽翔 气体质量流量计 - MF4000可用于过程控制、大气采样等各种工业应用等等。

  • 2019-10-12
  • 发表了主题帖: CSR8670 — 说说什么是ANC、CVC、DSP降噪

    1、CVC和DSP降噪:       消费者在选购蓝牙耳机时,总会听到商家在宣传耳机所具备的CVC、DSP降噪功能,不管听过N多商家这样的描述,可不少消费者依然不是很明白这两者之间的区别,针对这样的一个技术问题,我们今天来科普下这两者的工作原理及区别。         DSP是英文(digital signal processing)的简写,其工作原理:麦克风收集外部环境噪音,然后通过耳机内部的降噪系统功能,复制产生一个与外界环境噪音相等的反向声波,将噪音抵消,从而达到更好的降噪效果。         CVC是英文(Clear Voice Capture)的简写,是一种软件降噪技术,其原理是通过耳机内置的消噪软件及麦克风,来抑制多种类型的混响噪音。 两者的区别: 1、针对对象不一样,CVC技术主要针对通话过程中产生的回声, DSP主要是针对外部环境中的高、低频噪声。 2、受益对象不同,DSP技术主要使耳机使用者本人收益,而CVC主要使通话的另一方受益。 归结而言采用DSP和CVC降噪技术的耳机,都能有效降低通话外部环境的噪音,显著提高耳机的通话、听歌音质。如纳音科技最新推出的 jetblue M8 磁控蓝牙耳机,就具备DSP和CVC这两种降噪功能,在音质上表现很出色。 2、ANC降噪:   ANC指Active Noise Control,主动降噪。基本原理是降噪系统产生与外界噪音相等的反向声波,将噪音中和。图1是feedforward式主动降噪耳机的示意图。ANC芯片放置在耳机内。Ref mic(reference microphone)在耳机耳罩上,采集环境噪音。Error mic(Error Microphone)在耳机内,采集降噪处理后的残差噪声。Speaker播放ANC处理后的anti-noise。  图1    原理   图2    图2是ANC系统的原理图,一共三层,用虚线分隔。最上一层primary path是从ref mic到error mic的声学通道,响应函数用表示;中间一层是模拟通道,其中secondary path是adaptive filter输出到返回残差的通路,包括DAC、reconstruction filter、power amplifier、speaker播放、再采集、pre-amplifier、anti-aliasing filter、ADC;最下一层是数字通路,其中adaptive filter不断调整滤波器权系数来削减残差,直到收敛。最常用的方案是用FIR滤波器结合LMS算法来实现adaptive filter。简化图2,得到图3。     图3      先简要说几句adaptive filter和LMS(Least mean square)算法的原理,再说图3。如图4,给定输入和desired output ,adaptive filter每次迭代会更新系数,使其输出与之差越来越小,直到残差足够接近0且收敛。LMS是adaptive filter的一种更新算法。LMS的目标函数是瞬时误差的平方,为了minimize目标函数,对其应用梯度下降就得到算法的更新公式。(这种利用gradient descent来最小化某个objective,从而得到待求参数的更新公式的算法思想非常常见,比如linear regression。)采用FIR滤波器的LMS算法的更新公式为:,其中为step size。如果随着迭代进行调整的大小,就是变步长的LMS算法。   图4      再来说图3。这里adaptive filter输出后还要经过才去和desire output比较,会引起instability,用文献的话说,“the error signal is not correctly ‘aligned’ in time with the reference signal”,破坏了LMS的收敛性。(这里还没弄懂什么意思T__T)一种有效的方法是FXLMS(Filtered-X LMS),也就让x(n)经过再输入给LMS 模块, 是的估计。FXLMS的objective: 所以gradient=,其中未知,用其estimate近似,所以FXLMS的更新公式是其中 。     当adaptive filter收敛时,,因此。也就是说,自适应滤波器的权系数是由耳机的primary path和secondary path决定的。耳机的primary path和secondary path相对稳定,所以adaptive filter的权系数也相对稳定。因此为实现简单,某些厂家的ANC耳机的权系数在出厂时就确定了。当然这种ANC耳机的听感体验明显不及具有真正自适应意义的ANC耳机,因为在实际情况下,外部噪声相对耳机的方向、不同温度等因素会对耳机的通道响应有影响。

  • 发表了主题帖: 给开发板烧写程序的N种方式

    这里分享出来主要是让大家对烧写程序有个广阔的了解。        开发板没有BootLoader的烧写(flash中没有任何内容时,或误擦除uboot),仅用于烧写bootloader和裸机程序到flash上。 1. 并口Wiggler JTAG调试板 配合HJTAG软件,可以烧写nandflash和norflash,并口速度较慢  (需要用到并口,现在笔记本电脑基本没有并口了,这个方法局限性很大) 2. HJTAG USB仿真器 配合HJTAG软件,可以烧写nandflash和norflash,速度极快,适用于没有并口的电脑 3. Jlink V8仿真器 配合JFlash Arm软件,只能烧写Norflash(也可间接烧写Nandflash,间接烧写到Nandflash是借助sdram来实现烧写的,稍微有一点难,这里公司为了节约成本很多都采用nandflash来启动内核,norflash和nandflash这里区别就明显体现出来了,norflash可以像内存一样直接操作,nandflash只能通过控制寄存器来操作,这里大家一定明白过来,硬件上的差异也是很大的),适用于没有并口的电脑         开发板有u-boot,使用uboot烧写,flash中需要能正常运行uboot,适用于烧写bootloader,kernel和rootfs 1. USB口,S3C2440提供的uboot集成了USB Download的功能,可配合三星提供的DNW软件,方便的下载程序(缺点是烧写速度太慢,优点是三星厂家提供制作好的u-boot源码)  DNW软件有windows版本和linux版本,其中linux版本较方便使用,并且稳定。 2. 网口,也是一种速度较快的下载方式,uboot中集成了tftp Download功能,可配合任意一种tftp Server软件实现下载程序。同样可用于windows和linux平台,推荐大家使用这种方式来下载,因为速度非常的快。 3. 串口,使用串口Xmodem协议下载程序,相比USB和网口,速度较慢,不推荐此方式 4. U盘,不需要PC机软件的支持,将U盘插在板上,就可以利用uboot下载U盘中要烧写的文件,并可实现全自动烧写 5. SD/TF卡,等同于U盘烧写程序

  • 发表了主题帖: 烧录文件到开发板操作

    软件工具准备: 1.Jlink烧录软件(Setup_JLinkARM_V410i.exe)                                       2 .Windows下 tftp软件安装(tftp32.exe)                                     3.远程登陆软件(securecrt或Putty)                                      4. USB转串口驱动安装(PL-2303)   一、将内存初始化程序bootstrap下载至SRAM并运行 1.打开J-Link Commander,将fl2440开发板拨至nand flash启动,也就是按下电源 电源开关。 2.以下是常用命令: speed 12000:设置下载速率为12M。 r:reset,复位命令。 h:halt,停机、也有暂停的功能。 loadbin <filename> <address>:下载filename文件到地址address上。 setpc:设置PC寄存器的值。 3.具体操作  J-Link>speed 12000  J-Link>h  J-Link>loadbin E:\images\bootstrap-s3c2440.bin 0  J-Link>setpc 0  J-Link>g **************************************************************************************************************************************************** 说明:      (1).speed 12000意在设定开发板频率,也就是设置开发板的下载速率      (2).因为选择从nand flash启动时;0x00000000是映射到4K的SRAM中的,SRAM不需要初始化、即可直接运行程序。                 bootstrap-s3c2440.bin是郭工写的一段很简单的内存初始化程序,其实它就是uboot.bin文件的前4k代码;注意大小必须等于或小于4KB。 **************************************************************************************************************************************************** 二、下载u-boot程序至SDRAM内存   J-Link>h   J-Link>loadbin E:\images\u-boot-s3c2440.bin 0x33f80000   J-Link>setpc 0x33f80000   J-Link>g ************************************************************************************************************************************************** 说明:将这个bin文件载入到33f80000这个内存地址 **************************************************************************************************************************************************** 三、使用u-boot烧录我们的程序至nand flash 1.设置uboot环境变量  u-boot>nand scrub                                      /*擦出整个nandflash所有分区,也就是格式化nandflash*/  u-boot>set ethaddr 00:11:22:33:44:55  /*设置网卡MAC地址 */  u-boot>set ipaddr 192.168.1.2                  /*设置网卡ip地址,也就是开发板的ip地址 */  u-boot>set serverip 192.168.1.168           /*设置tftp服务器地址,也就是本机以太网卡的ip地址 */  u-boot>save                                             /*保存uboot环境变量*/ 2.烧录u-boot-s3c2440.bin程序  u-boot>tftp 30008000 u-boot-s3c2440.bin   /*下载u-boot程序到sdram内存中*/  u-boot>nand erase 0 100000                      /*擦除u-boot存放相应分区*/  u-boot>nand write 30008000 0 60000       /*三个数字对应首地址,偏移量,文件大小,该命令是将u-boot从内存中写到nandflash的相                                                                       应分区*/ 3.烧录linux内核  u-boot>tftp 30008000 linuxrom-s3c2440.bin     /*下载linux内核文件到sdram内存中*/  u-boot>nand erase 100000  800000                 /*擦除linux内核及相应的分区,100000是分区起始地址,800000是分区的大小,擦                                                                                  除是整个分区的擦, 不能擦除一个分区的一部分,否则会出错*/  u-boot>nand write 30008000 100000 800000  /*将linux内核从内存中写到nandflash相应分区*/  

  • 回复了主题帖: 怎么把PC端的执行文件下载到开发板上?

    电脑要和开发板都接到服务器上

  • 2019-10-10
  • 发表了主题帖: 介绍一下多器件 C2000 编程器 C2000-GANG

       C2000 Gang 编程器是一个 C2000 器件编程器,可以同时对多达八个完全相同的 C2000 器件进行编程。C2000 Gang 编程器可使用标准的 RS-232 或 USB 连接与主机 PC 相连,并提供灵活的编程选项,允许用户完全自定义流程。  C2000 Gang 编程器配有扩展板,即“群组分离器”,可在 C2000 Gang 编程器和多个目标器件间实施互连。还提供 8 条电缆,可扩展接口与 8 个目标器件相连(通过 JTAG 或 Spy-Bi-Wire 连接器)。编程可借助 PC 或作为独立设备实现。还提供基于 DLL 的 PC 端图形用户界面。  通过 RS-232 或 USB 接口快速可靠地对 C2000 器件编程 多个编程模式: - 交互模式:借助 C2000 GANG 编程器 GUI,在与 PC 连接时进行编程。 - 从图像中编程:可存储含有配置选项和代码文件的图像。它允许用户独立对 C2000 器件进行编程,而无需 PC。 - 从脚本中编程:允许开发人员自动执行更复杂的编程程序。 直观的 GUI 可用于配置、编程和测试生产设置 SD 卡插槽适用于存储图像 LCD 屏幕适合无需 PC 下的方便编程 同时支持多达 8 个目标 支持所有当前和未来 C2000 器件   详细的技术文档:C2000 Gang Programmer (C2000-GANG) User's Guide

  • 发表了主题帖: TMS320F24x与PC机串行通信接口设计及应用

           TMS320F24x是美国ti公司tms320系列定点数字信号处理器(dsp)之一,tms320f240是f24x系列面向数字控制芯片的典型代表。由于tms320f240并不具备人机界面,在实际使用过程中,需要为它提供一个人机接口或上层控制接口,以便于观察控制效果或传递必要的控制信息。因此,实现tms320f240与pc之间串行通信接口的设计方法,具有较高的实用价值。     f240芯片内部集成了一个串行通信接口(sci)模块,该模块是一个标准的通用异步接收/发送(uart)通信接口,通信接口有scitxd(sci发送输出引脚)和scirxd(sci接收输入引脚)两个外部引脚,引脚的信号电平为ttl类型。而pc机串口的异步串行通信基于rs232c标准,两者的信号逻辑电平不一致,必须进行信号电平转换。选用内部含有电压倍增电路的电平变换芯片max232,max232有两对收/发单元,实现dsp与pc之间的串口通信只需一对收/发单元即可,在完成dsp与pc的正常通信任务的基础上,利用另外一对收/发单元,扩展了实现pc与dsp的双向复位功能。当dsp控制器程序出错、监控对象异常或需要控制程序重新运行时,可以直接从上位pc发控制指令,达到复位下位机的功能。同样,也可以从dsp端复位pc或给pc发特定的命令信号。     以rs232c通信标准进行通信,在保证通信准确性的前提下,通信距离一般以不超过12m为宜,在工业控制现场很受限制。为保证硬件设计的兼容性和易扩展性,能够应用于不同场合,在dsp硬件电路板端还采用了一个max489芯片,添加了一个rs485/rs422通信接口。     实际使用过程中,系统在选择不同的通信标准时,切换十分方便。如图1所示,当跳线端子jump2与jump3的2、3脚短接时,scitxd接通max232芯片的t1i引脚,scirxd接通max232芯片的r1o引脚,即dsp的通信接口与max232芯片相连,此时系统采用rs232c的通信标准。当跳线端子jump2与jump3的1、2脚短接时,scitxd接通max489芯片的di引脚,scirxd接通max489芯片的ro引脚,即dsp的通信接口与max489芯片相连,此时系统采用rs485/422的通信标准,pc端只需添加一个rs232c/rs485转换器即可进行通信接口电平转换。     uart通信对噪音比较敏感,特别是脉冲边沿抖动。所以,为了确保uart能够正确工作,必须能够检测它的开始和结束字节。也就是说,需要一定的数据包格式,即使是使用一个uart端口,在这个数据包中的每一个字节也都要编成uart格式。因此在异步串行通信中,收、发双方必须事先规定字符格式、采用的波特率,以及时钟频率和波特率的关系。     这些规定是通过初始化设置与串行通信有关的寄存器来实现的。本通信系统中,规定字符格式为:每一帧的数据占10位,一位奇校验位,8位数据位,1位停止位。中间的8位数据位即为有效的通信传输字节。双方的波特率设置为19200bps。同时,为了增强通信的可靠性,减少通信的误码率,规定了通信双方收发数据包的协议如表1所示。     特征码选用0xff、0xaa、0x55这3字节为发送数据包的前导数据,这是因为这几字节在传输噪声中同时出现的几率很小,特征码起到向接收方表明有数据发送过来的作用,通知接收方可以开始接收有效数据;字节数是数据包中除了字节数这一项之外,其他所有项字节的长度;有效数据字符串是通信发送方要传送的有效数据;校验和是数据包中除了校验和这一项之外所有项字节的无进位累加和,用于校验通信是否正确。     同时,在通信过程中约定了双方的软件握手方法。为了不使通信过于复杂,提高通信速度,可以直接将握手信号0xff嵌入到数据包中。软件握手协议规定如下:pc定时发送符合通信协议规定的数据包,dsp接收到的第四字节若为握手信号0xff,则将校验正确后的有效数据存储,并从中分解有效字节信息,然后回送相同格式的数据包。若pc接收到的数据包的第四字节不是0xff,则摒弃该数据包。     在dsp端的软件程序设计中,通过中断方式接收pc发送过来的数据包,握手并校验确认后接收有效数据,再将pc所需的数据打包回送。基于dsp功能模块化的特点,其串行通信汇编程序的编制主要分三个步骤:     (1)初始化设置时钟源模块,得到所需的cpuclk和sysclk(因为计算波特率时与之有关);     (2)设置sci模块,初始化各sci控制寄存器;     (3)编写串行通信中断服务子程序,即可完成dsp与pc之间的串行通信。     在串行通信中断服务子程序的编制过程中,可完成正常的数据通信任务。如果需要利用软件来实现dsp与pc的双向复位,则可将图1中的跳线端子jump1的1、2脚短接,串口的dtr引脚通过上拉电阻接通电源,将jump4的2、3脚短接,max232的第二路收/发单元的发送引脚接通dsp的复位端hostrest。系统上电之后,dtr呈现高电平状态,若系统运行过程中出现dsp控制器的程序出错、监控对象异常时,可以通过在上位机端执行特定的复位操作,在程序中使pc串口的dtr引脚状态产生由低到高的电平变化,通过max232芯片的第二路通信收/发单元,将输出电平传递给hostrest,最后提供给dsp的复位引脚rs,使得复位引脚rs上同样出现低到高的电平变化,从而使dsp复位,下位机dsp控制程序得以重新运行。同样的,当dsp端自行检测到通信数据不正常时,可以根据检测结果,自行发送复位信号。通过指令clrxf,置位xf引脚为低电平,经由max232芯片的第二路通信收/发单元,串口的cts引脚接收到低电平信号,pc端程序若查询到cts电平出现由高到低的电平变化时(触发comevcts事件),自动改变程序运行流程,使得pc端的通信程序重新开始,以期恢复通信的正常。当然,也可以通过在dsp端改变xf引脚电平状态,作为给pc发送的特定命令信号,相当于在dsp与pc之间预留了一个相互联系的通信接口。     上位pc串行通信程序在windows2000平台下采用visualc++6.0实现。vc自带的activex控件microsoftcommunicationscontrol,即mscomm控件,提供了对windows通信驱动程序的api函数接口,为应用程序提供了通过串行口收发数据的简便方法。因此直接在应用程序中嵌入mscomm控件,可以方便地进行计算机串口的通信管理。即只需设置mscomm控件的相应属性,调用控件的相应方法和事件,按照通信协议的要求定时发送数据包,上位机即可完成相应功能,实现数据通信任务。     mscomm控件提供下列两种处理通信的方式:事件驱动方式和查询方式。mscomm控件的主要属性并给出了这些属性在程序中的设定值。上位pc一般采取事件驱动的方式接收来自于下位机dsp的二进制数据。事件驱动方式的工作原理类似于中断,当有通信事件发生时(如发送数据、接收数据等),就会触发oncomm事件,在该事件的处理函数中调用getcommevent()函数,通过返回值即可确定是哪类事件,再做出相应的数据处理,完成双方之间的通信。     通过串行口完成dsp与pc之间的通信,具有硬件接口简单、数据传送距离远以及开发周期短、成本低的特点,已经成功应用到研制的机器人作业系统中。本文介绍tms320f240与pc串行通信接口的设计方法具有一定的通用性,对tms320f241/f243/c242以及tms320lf2406/lf2407等tms320f24x系列芯片具有很好的参考作用。

  • 发表了主题帖: msp430超声波测距思路

    本帖最后由 灞波儿奔 于 2019-10-10 09:46 编辑 LCD初始化,显示LOGO; 给超声波模块一个触发信号; 检测超声波模块的输出信号,如果监测为高,启动定时器计时;如果检测为低,关闭定时器; 根据定时器计时时间和公式算出距离; 将距离送给LCD显示;                 LCD128-64 RS(CS)片选信号=P3.0 = 1; WR(SID) = P3.1;//数据 EN(SCLK) = P3.2;//时钟 CS1(PSB) = P6.2;//接地,串行模式 单片机源程序:         #include  <msp430x14x.h>         #include "12864.h"         uchar Edge=1;//当前触发沿         uint RiseCapVal;   //上升沿时刻捕获值存放变量         uint TA_Overflow_Cnt; //TA溢出次数存放变量,可能距离远超过65535         unsigned long int Period;   //脉宽存放结果变量,高电平时间         unsigned long int S;       // 定义距离长度,单位厘米                             void Conut(void)             {                          disbuff[1]=S%1000/100;                disbuff[2]=S%1000%100/10;                disbuff[3]=S%1000%10 %10;                LCD_set_xy( 3, 4 );                LCD_Write_number(disbuff[1]);                LCD_Write_number(12);                LCD_set_xy( 3, 5 );                LCD_Write_number(disbuff[2]);                LCD_Write_number(disbuff[3]);                                             }                   #pragma vector=TIMERA1_VECTOR         __interrupt void Timer_A(void)         {                     switch(TAIV)           {             case 2 :if(Edge==RISE)                       {                         RiseCapVal = TACCR1;                         TACCTL1 |= CAP+CM_2+CCIS_1+SCS+CCIE;//改为下降沿捕获                         Edge = FALL;//下降沿捕获标志                       }                     else                       {                                   //_DINT();                         Period = TACCR1-RiseCapVal;  //这里要注意是否考虑溢出,跟测试距离有关,希望大家拓展                         S=(Period*17)/100;   // 距离计算 s=340m/s*Period/2*10^(-6)*1000(mm)                         TACCR1 = 0;                         TACCTL1|= CAP+CM_1+CCIS_0+SCS+CCIE;//改为上升沿捕获                         Edge = RISE;//上升沿捕获标志                         //_EINT();                       }                      break;             case 4 : break;             case 10: TA_Overflow_Cnt++;   //溢出标志                      break;           }         }                             void init_timerA(void)         {           TACTL   |= TASSEL_2+MC_2+TAIE+TACLR+ ID_3;//SMCLK,8MHz,8分频,连续计数,中断允许,计数器清零           TACCTL1 |= CAP+CM_3+CCIS_0+SCS+CCIE;//捕获模式,上升沿下降沿都捕获(CM_3),CCI1A输入,同步捕获,中断允许         }                   void init_IO(void)         {           P1DIR |= BIT1;   //P1.1输出,普通I/O           P1DIR &=~ BIT2;  //P1.2输入           P1SEL |=  BIT2; //P1.2第二功能,捕获输入                     P1OUT &=~BIT1;  // 开始低电平,控制驱动波形发生         }                   void init_clk(void)         {             uchar i;             BCSCTL1&=~XT2OFF;   //打开XT振荡器             BCSCTL2|=SELM_2+SELS;//MCLK 8M and SMCLK 8M             do             {               IFG1 &= ~OFIFG;//清除振荡错误标志               for(i = 0; i < 0xff; i++)  _NOP();//延时等待             }             while ((IFG1 & OFIFG) != 0);//如果标志为1继续循环等待晶振起振             IFG1&=~OFIFG;         }                             void main(void)         {                       /*下面六行程序关闭所有的IO口*/             P1DIR = 0XFF;P1OUT = 0XFF;             P2DIR = 0XFF;P2OUT = 0XFF;             P3DIR = 0XFF;P3OUT = 0XFF;             P4DIR = 0XFF;P4OUT = 0XFF;             P5DIR = 0XFF;P5OUT = 0XFF;             P6DIR = 0XFF;P6OUT = 0XFF;                                 WDTCTL = WDTPW + WDTHOLD;            //关闭看门狗             P6DIR |= BIT2;P6OUT |= BIT2;         //关闭电平转换             P6DIR |= BIT3;P6OUT |= BIT3;         //关闭电平转换                                           Ini_Lcd();             Disp_img(logo);   //显示欢迎使用本产品LOGO             delay_Nms(1000);             Ini_Lcd();             Lcd_Mark2();                       init_clk();             init_IO();           //初始端口设置             _EINT();               //开全局中断             while(1)             {                init_timerA();                P1OUT |= BIT1;    // P1.1 高电平,超过10us                delay_Nms(100);                P1OUT &=~BIT1;                delay_Nms(80);                Conut();                delay_Nms(80);       //80MS                                           }         }

统计信息

已有101人来访过

  • 芯币:1800
  • 好友:1
  • 主题:606
  • 回复:30
  • 课时:--
  • 资源:--

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言