This thread has been locked.

If you have a related question, please click the "Ask a related question" button in the top right corner. The newly created question will be automatically linked to this question.

快来讲述您和 TI MCU 的故事!(活动已结束)

Other Parts Discussed in Thread: LM3S3748, TMS320F2808, TMS320F2812, LM3S811, TMS570LS20216, MSP430F149, MSP430F5438, MSP430F247, ADS1110, MSP430F2132, MSP430F147, MSP430F169, MSP430F2618, LM3S6911, LM3S8962, LM3S5749, MSP430F1611, MSP430FE425, CC2530, CC2430, MSP430F4270, MSP430F5438A

2011年 9月 1日到 9月 16日,快来发贴分享您在学习或工作中关于应用 TI MCU 产品(MSP430、C2000、Stellaris)的各种技巧与心得、各种疑问和不解。每篇主题不少于 150字,如果是技巧心得和疑惑的帖子,请详细写出获得心得的具体过程或者经过哪些步骤的试验仍未成功。

我们期望德州仪器在线技术支持社区为大家提供一个交流经验、互相学习的平台。每个 ID 不限制参与次数,但每个 ID 只有 1 次获奖机会。(TI工程师团队具有最终解释权。)

快来讲述您和 TI MCU 的故事,精巧 4G 名片 U 盘等您拿!

所有此次活动的贴子请在此主题贴下以“回复”形式发表!我们将以此主题下的发贴作为获奖信息!热切期待大家的参与!



  • 中午休息,分享一下我自己在学TMS320F2812DSP遇到的一些小问题。纯粹自己理解,错误之处望见谅,多指正。

      首先,是延迟函数的使用:在做电机调速时,发现自己用C简单编写的延迟delay函数,会出现实际延迟时间与程序设定时间误差较大的情况,查阅一些资料,发现可以利用例程里已有的延迟汇编文件,编写较为准确的延迟函数DELAY-US(),且调用简单可靠。具体步骤如下:1,下载DSP281x_usDelay.asm文件,将内容改为

                extern void DSP28x_usDelay(Uint32 Count);

                             .def _DSP28x_usDelay

                             .sect "ramfuncs"

                               .global  __DSP28x_usDelay

                               _DSP28x_usDelay:

                              SUB    ACC,#1

                         BF     _DSP28x_usDelay,GEQ    ;; Loop if ACC >= 0

                            LRETR

                            放于工程的source中;

    2,在MOTOR.H文件中定义

       #define CPU_RATE  6.667L  // for a 150MHz CPU clock speed (SYSCLKOUT)

           #define DELAY_US(A)  DSP28x_usDelay(((((long double) A * 1000.0L) / (long double)CPU_RATE) - 9.0L) / 5.0L)

    3,在GlobalPrototypes.h中定义

              extern void DSP28x_usDelay(Uint32 Count);

    4, 在程序中直接调用DELAY_US(A),例如  DELAY_US(1000L);,表示延迟1ms 。

    其次,是2812flash烧写的问题,具体步骤如下:(1)  下载烧写FLASH配套CMD文件、LIB文件以及起始代码asm文件。

    CMD文件名称:DSP281x_Headers_nonBIOS.cmd

    CMD文件名称:Flash.cmd

    LIB文件名称:rts2800_ml.lib

    ASM文件名称:DSP281x_CodeStartBranch.asm

          (2)配置C文件

    配置好主程序的C文件,才能将FLASH成功烧录,并且将FLASH中的文件拷贝到RAM中运行。

    关于C文件的配置。

    首先在F2812.CMD文件中,我们可以看到有关于加载FLASH到RAM的内容:

      ramfuncs            : LOAD = FLASHD,

                            RUN = RAML0,

                            LOAD_START(_RamfuncsLoadStart),

                            LOAD_END(_RamfuncsLoadEnd),

                            RUN_START(_RamfuncsRunStart),

                            PAGE = 0

    以及在C文件中调用FLASH 到RAM的函数memcpy,将它放在系统初始化(InitSystem();)之后即可:

    InitSystem();

    memcpy(&RamfuncsRunStart,

                   &RamfuncsLoadStart,

                   &RamfuncsLoadEnd - &RamfuncsLoadStart);

    Initflash();

    关于ramfuncs,则在系统初始化中定义即可。如:sysctrl.c中

    #pragma CODE_SECTION(InitFlash, "ramfuncs");

    (3)我们需要定义所用变量:

    extern Uint16 RamfuncsLoadStart;

    extern Uint16 RamfuncsLoadEnd;

    extern Uint16 RamfuncsRunStart;

    我的这些定义都是:DSP281x_GlobalPrototypes.h 当中,当然,也可以放在其他系统初始化的地方。

    Memcpy这个函数应该是rts2800_ml.lib库文件中自带的,不需要我们定义。

    (4)烧写成功后的注意事项:

    1.        一定要拔除仿真器(JTAG端),给电路板重新上电,方能实现FLASH启动。

    2.        注意MP/MC引脚的电压。0为方式MC来作为计算机模式启动,3.3V为方式MP作为微处理器模式启动。

    3.        由于GPIO引脚的F4\F12\F3\F2决定了DSP2812的启动顺序,而从FLASH必须要在F4(SCITXDA)为1,而F12\F3\F2随意的状态下启动。请大家启动前确认F4引脚电压。

  • 工作之余,分享一下我自己在调试Stellaris MCU: LM3S3748时遇到的一个问题,带给大家,望入门者能够快速的解决问题。错误之处望见谅,请大虾们指正!希望能和大家共同进步! 我的QQ:2547457966,email: viken@126.com

    问题1:关于在调试,SPI 时序时,遇到的问题。

    现象,LM3S3748做主机使用,FM25L16-G为从设备,用示波器检测SPI的时序,主机发出的时序正常,从机就是不响应。

    解决办法:

    在 读/写 FRAM的子程序中,在发送命令或者数据后,置位 CS 线之前,加入适当的延时。

    附解决问题的部分子程序,

    void MSPI_Init( void )

    {    

            SysCtlPeripheralEnable(SYSCTL_PERIPH_SSI0);

            SysCtlPeripheralEnable(SYSCTL_PERIPH_GPIOA);

            SSIDisable(SSI0_BASE);

            GPIOPinTypeSSI(GPIO_PORTA_BASE, GPIO_PIN_5 | GPIO_PIN_4 | // GPIO_PIN_3 |  GPIO_PIN_2);

            GPIOPinTypeGPIOOutput(GPIO_PORTA_BASE, GPIO_PIN_3);

            GPIOPadConfigSet(GPIO_PORTA_BASE, GPIO_PIN_3, GPIO_STRENGTH_2MA,  GPIO_PIN_TYPE_STD);

            SSIConfigSetExpClk(SSI0_BASE, SysCtlClockGet(), SSI_FRF_MOTO_MODE_0,  //SSI_FRF_NMW,   // SSI_FRF_MOTO_MODE_0

            SSI_MODE_MASTER, 1000000, 8);

             // Enable the SSI0 module.

            SSIEnable(SSI0_BASE);

            FM25H20_DeCS( );

    }

    uchar MSPI_Transfers( uchar data )

    {

            uchar i;

            uchar RdData;

             while( !( HWREG( SSI0_BASE + SSI_O_SR ) & SSI_SR_TNF ) );        // Wait until SSI Transmit FIFO Not Full .  

              HWREG( SSI0_BASE + SSI_O_DR ) = data;                                           // Write the data to the SSI.

              while( !( HWREG( SSI0_BASE + SSI_O_SR ) & SSI_SR_TFE ) );      // Wait until SSI Transmit FIFO is Empty .

              for( i = 0; i < 200; i++ );                                                                                 // Delay XX Cycle after set CS line.

              RdData = HWREG( SSI0_BASE + SSI_O_DR );

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

              return RdData;

    }

    // Sets the Write Enable Latch

    void FM25H20_WriteEnable( void )

    {

               FM25H20_CS( );                                                             // Select Device

               MSPI_Transfers( FM25H20_WREN );                        // Write Enable Op-Code

               FM25H20_DeCS( );                                                       // Deselect Device

    }

    // Reads the Status Register
    uchar FM25H20_ReadStatus( void )
    {
              uchar temp;
     
              FM25H20_CS( );                                                             // Select Device
              MSPI_Transfers( FM25H20_RDSR );                        // Read Status Register OpCode
              temp = MSPI_Transfers( 0x00 );                                 // Read Status Register
              FM25H20_DeCS( );                                                       // Deselect Device

              return( temp ); 
    }

  • 我们现在开发的一款化工在线仪表。里面用到MSP430F2132IPW。这款产品确实好用。编程资料多,编程效率高,程序可读性强等优点使我们的工作效率大大的提高。它的稳定性和可靠性也是我们非常认同的。它的片内资源丰富,大大的简化了在线仪表的外围电路,进一步的提高了仪表的可靠性和抗干扰性能。MSP430F2132IPW确实是一款非常出色的单片机!我们在开发其他的仪表的时候还会选择它的!

  • 2000系列MCU算是伴随我成长的MCU。本科时候基本上什么实践应用的东西都没学过,只上过单片机的课程,但是也没有做过实验,那时候都不知道单片机除了51系列之外还有那么多种,更不要提什么DSP了,只记得老师上课时候提过现在本科生掌握了DSP,去找工作就很容易,因而觉得DSP应用应该是奇难无比的,就被吓倒了。

    读研以后,一次老师给的任务是使用2406编程,那时候觉得是世界末日,一点不懂,而且2406是16位的MCU,许多数据处理起来要用汇编语言才可以。疯狂的从图书馆找书来看,问师兄,师兄说还是先把软件装好,连上小系统板一边仿真一边摸索比较快,可是那时候没明白师兄的话,觉得还是要看书,把芯片的结构、功能模块都看懂才行,后来事实证明“不听前辈言,吃亏在眼前”,走了许多弯路,浪费很多时间。

    倒不是说理论不重要,当然要看,可是当你把CCS安装好了,小系统可以连接上,可以运行了,一方面可以给你增强信心,另外一方面,看不明白的地方结合实例运行运行,对理解非常有帮助。另外,对于许多初次接触DSP的人来说,不要被别人的话吓到。DSP功能强,但是功能强不代表难掌握,它就是一个控制器,和其他单片机没什么本质区别,功能强只会使他更加好用。

    初次接触DSP的时候还要充分利用TI的技术支持,遇到身边人也没法解决的问题时,可以发邮件咨询,另外网站的设计支持里面有很多例程,非常实用。

  • 我一直在学习使用f2812。准确的说是在学习关于matlab与dsp在环仿真的方法。TI公司与matlab良好合作促成了对dsp更快捷的编程方式。利用maltab便捷的优化方法、控制方法,理论与实践得到完美统一。这个过程也需要一些过程和努力。对此我给出我的经验,仅供参考:

    1匹配合适的ccs版本与matlab版本。

    对于一上来接触这一块的人来说。可能不知道这个的重要性。但是的确非常关键

    2dsp的flash写保护解锁

    编程时往往会出现这样的情况:matlab成功生成程序,也连接上dsp了。但就是无法下载。这个原因就在于此。解决方法是在ccs中首先load gel,然后再去找flash对应的解锁选项。

    3maltab中的模块不是想用就能用的。有些函数必须经过一定的变化才能使用

    举一个我做过的例子:要实现一个已经训练好的神经网络,在编译中会报错这是因为神经网络模块内部会有一些算法不被支持。行之有效的解决方法就是将该函数在help中搜索找到可以替换的函数。

    4注意采样时间问题。采样时间往往应该长于计算时间。

    有其他问题可以qq:392803559

  •        非常感谢TI为大家提供一个这么好的交流平台,由于我还只是一名研究生,对DSP还不是很精通,不过也希望能跟大家分享一点心得。

       我曾使用过的DSP型号是TMS320F2812和TMS320F2808,项目内容是利用2者的CAN总线模块,组建一个数据采集系统,3点心得:

       1.在用不同时钟频率的DSP组建CAN网络时,一定要注意CAN波特率的设置,由于CAN的波特率取决于系统时钟,系统时钟不同时,便会得到不同的波特率,造成各节点无法通信,一定要根据每个节点自身的时钟频率和计算公式进行设置。

       2.调试2812时,最好不要在上电的情况下用示波器探头测试引脚,这么做比较危险,容易损坏芯片,我就发生了这样的悲剧,希望大家引以为戒。

       3.关于2812的功耗问题,提醒大家在设计时予以考虑,虽然2812已经属于低功耗产品,但和一些常用的51单片机相比,功耗还是高出不少了,我当时就是没有考虑到这些,使用一片最大负荷250mA的7805为两个节点供电,CAN总线一开始通信就出错,经过长时间的测试才发现是电源供电不足,两个节点同时通信时,电源的供电电流需要将近200mA,我的7805无法正常工作,所以出错,希望大家注意。

       水平较低,多多指教。

  • 第一次接触TI的MCU是刚参加工作的时候,主要是2808这款控制器,在网上疯狂下载资料、囫囵吞枣的看看,大概学习了一周以后就开始做项目的下位机的软件开发设计,对于全新的环境和复杂的寄存器操作,拿到任务时,开始有些手足无措,只能啃手册,上网搜索资料等,大概再用了1周时间,基本上熟悉了开发环境,能够写出一些实用的程序来了,做了一些控制相关的开发,没有什么可以聊的。

    后来接触一些复杂项目,对于软件的实时性要求很高,中断占用了大量的CPU资源,开始重新架构软件,将部分中断中的程序放在中断外执行,去掉某些不必要的中断,减少压栈出栈的次数,经过这样的修改,极大的提高了系统的资源利用率,原来大概100us左右的频率的中断就来不及响应,修改后即使20us左右的频率的中断也没有问题。

    还碰到一个问题,就是在中断中执行一个查找算法,这个循环最恶劣的·情况是循环10000遍,导致中断占用时间过长,其他中断无法及时响应,修改了查找算法,增加了一个读指针,每次只需要判断是否在查找的目标位置就可以了,极大的降级了时间复杂度,系统性能得到了根本性的提高。

    从使用2808这款控制器以后,我觉得有以下几点切身体会:

    1)从算法上优化,提高的性能是最多的!O(∩_∩)O~,数学很重要!

    2)多做实验,实用仿真器是提高开发效率的好办法,前提是你有一个好的仿真器,别是那种质量很差的,如果你从椅子上站起来,旁边的仿真器就掉了,这样会搞死人的,本人深受其害啊!

    3)不太建议从代码级去一点一点抠,去做优化,我觉得如果出现了这种情况,那么在前期评估的时候工作做得不到位。从代码级优化,可能花了大量的时间,而成果却很少,往往还达不到效果。

    但是,我并不是说就不去了解和实践代码级优化,因为了解和实用这些,会提高技能,在以后编写代码的时候就将这些优化已经做好了,提高效率和工作质量。

    ps.啰嗦了一点!

     

  •    今天碰巧看到了这则信息,来分享一下我学习LM3S811的趣事……

       我是通过参加TI M3 DAY 获得LM3S811评估板的,拿到板子后心情很是激动,于是就立刻投入了学习中。

       开始没有看任何PDF的介绍就尝试着把软件附带的例程下载进了芯片中,有一个例程是JTAG-GPIO,这个例程下进去后接着就不能再下载别的例程了,那时候估计是锁住了,心想这下完蛋了,可是当我重装了驱动后竟然奇迹般的好了,后来我认真地看了看《JTAG防锁死和LM3S系列几个基本例程》,还有看了看在网上找到了M3的资料,看后第一感觉是M3其实并没有传说中的那么难学,倒是感觉很容易学的。

       仅仅玩单片机无非就是对寄存器的配置(比如PX=0X…),但是玩M3不是这样的,编写M3的程序时主要是对函数的调用,对有参函数进行参数设置和匹配以及灵活运用带有返回值的函数,但是一系列函数的原型我还无从得知,我猜应该在driverlib.lib中。

       关于JTAG的防锁死功能其实是很简单同时又很有趣的:

    #define     KEY_PERIPH             SYSCTL_PERIPH_GPIOC  //宏定义 加强程序的可读性

    #define     KEY_PORT               GPIO_PORTC_BASE

    #define     KEY_PIN                GPIO_PIN_4

     

       void JtagWait(void)

    {

        SysCtlPeripheralEnable(KEY_PERIPH);             //  使能KEY所在的GPIO端口      (GPIO C)

     

        GPIOPinTypeGPIOInput(KEY_PORT, KEY_PIN);        //  设置KEY所在管脚为输入

     

        if (GPIOPinRead(KEY_PORT, KEY_PIN) == 0x00)   //  若复位时按下KEY,则进入

           {

                while(1);                           //  死循环,以等待JTAG连接

           }

        GPIOPinIntDisable(KEY_PERIPH,KEY_PIN);          //  禁止KEY所在的GPIO端口中断

    }

     

    LM3S811评估板上用户按键是PC4  JtagWait函数放在主程序的首位置。

    当复位后先判断按键,如果没有按下程序继续向下执行,如果按下则死循环等待。

    试想一下如果将JTAG作为GPIO后程序将不能下载进去,如果程序中加入JtagWait函数,那么先按下复位键再按下用户键然后松开复位键(此时保持用户键按下少许),则此时程序停在while(1);处,这时候JTAG并没有作为GPIO,因为程序停在while(1);处而并没有执行后面的程序(后面的程序将JTAG当做GPIO使用了),然后接着下载你编好的程序(有时候会不太灵敏,多试几次就好了)

    有了JtagWait函数后就不用再担心芯片被锁死了。

     

       后来又编写了几个流水灯程序,算是稍稍入门了。(当然我觉得入门单片机的基础是学会 1时钟部分 2定时器 3中断)  呵呵 个人见解

       前几天用M3做了一款乒乓球游戏(在TFT彩屏上面实现的)

     

       做这款游戏使用到M3的内部资源有TIMER0TIMER1及其中断、外部中断(用来进行键盘输入)等,游戏分为四关,每一关速度递增(通过配置晶振来实现)。

       当然做的过程中也是遇到了好多困难。

       比如开始时我的外部中断用的GPIOPB0PB1,老是不能进入中断导致球拍不能运动,后来发现PB0PB1连接的是LED,后来把外部中断换为了PB2PB3,总算好了。

    //******************************GPIOB中断服务函数******************************************

    void GPIO_Port_B_ISR(void)

    {  

               unsigned long ulStatus;

          ulStatus = GPIOPinIntStatus(GPIO_PORTB_BASE, true);       // 读取中断状态

     

          GPIOPinIntClear(GPIO_PORTB_BASE, GPIO_PIN_2|GPIO_PIN_3);  // 清除中断状态,重要

     

          if (ulStatus & GPIO_PIN_2)                                // 如果PB0 的中断状态有效

          {

                        TimerEnable(TIMER1_BASE, TIMER_A);/*启动定时器1*/

                                racket_dir=0;/*球拍朝左运动*/

          }

          if (ulStatus & GPIO_PIN_3)                                // 如果PB1 的中断状态有效

          {

             TimerEnable(TIMER1_BASE, TIMER_A);/*启动定时器1*/

                                racket_dir=1;/*球拍朝右运动*/

          }

    }

       …………

       当球拍没有接到球后就进入死循环,后来想了一下为什么不把死循环换为睡眠状态呢,不错就睡眠状态,呵呵  低功耗嘛

       今晚就先写到这里吧…………

  • 分享TMS570LS 系列MCU的学习心得

    由于这款片子推出时间不长,使用过的人也比较少。抽空写了这篇小小心得,希望这篇小小的心得能有益于打算在此平台开发或正在使用此平台开发的朋友们,此文仅作初次使用者入门级参考,更多高级应用等我以后整理好再与大家一起探讨。

    1. 学习时使用的MCU型号:TMS570LS20216,当然也可以使用这个系列的其他型号

    2. 学习中使用的硬件环境:

    开发板1——TMS570 MCU Development Kit (TMDX570LS20SUSB,TMS570 Safety MCU Demo Board), 这是一个USB接口开发套件,这个开发板自带一个mini emulator—TI XDS100V2 USB JTAG Emulator,直接接到PC的USB端口就可以调试程序,通过这个开发板可以了解一下TMS570的ADC, NHET, CAN, SCI等模块,有点不足的就是这个自带的emulator调试程序效率不高;

    开发板2——TMS570 MCU Development Kit (MCB board, motor control board), 这个板子功能比较强大, 调试程序速度也比较快, 含JTAG,ETM等接口,可以用来学习TMS570的所有模块,自带电机控制demo程序,建议使用这块板子来进行开发,稍微不足之处就是有很多外设引脚没有引出来,所以有些时候显得不太好测试;

    仿真器——XDS510 USB,JTAG调试,如果使用开发板2来开发就最好使用此emulator;

    3. 学习中需要使用的软件环境:

    IDE— Code Composer Studio Version: 4.2.3.00004;

    外设driver代码生成工具—HAL Code Generator version 2.09.000,Hardware abstraction layer code generator;

    NHET Assembler—HET Simulator version 1.1;

    NowECC-- Ecc generator tool;

    NowFlash—烧写程序用;

    4. 学习中需要参考的文档:

    Technical Reference Manual (TRM)-- spnu489b.pdf;

    TMS570LS Serial datasheet--tms570ls20216.pdf

    还有一些从TI网站上download的application note文档。

    5. 小小学习心得:

    这里强调一句,文档要用最新的文档,由于就版本的文档有一些信息是错误的,当然新文档也有错误的,但要少点。我在学习EMIF module时,最开始由于看的是旧版本的TRM文档,越看越晕,这章写的不好;后来得到新版本TRM后就好多了,这样不会走弯路;另外,在看TRM时,结合HAL Code Generator一起来学习,这样能加速学习进度和理解;

    6. 结束语

    一点小小的经验供大家参考,抛砖引玉,其他更多应用等我整理后再与大家一起探讨;

  • 第一次接触MSP430单片机,总体感觉非常不错,功能强,耗电低,执行效率高,JTAG调试方便直观等等。由于以前一直习惯使用51系列单片机,所以刚开始用MSP430,因为其功能强大,的确费了些功夫学习。还好多亏TI提供了很多样例程序,帮了不少忙。鉴于其功能强大、集成度、高灵活性好等优点,相信对产品开发的有很大的便捷性。

    借此机会也想交流下我在实际应用中碰到的一个问题。

    以下是一段MSP430内部FLASH应用样例程序,不过在调试过程中,程序可以完美的执行完前半部分,后半部分无法正常执行,暂时还没研究出是什么原因。本人用的是AQ430软件编程调试。

    //****************************************************************************

    //  MSP-FET430P140 Demo - Flash In-System Programming, Copy SegA to SegB

    //

    //  Description: This program first erases flash seg A, then it increments all

    //  values in seg A, then it erases seg B, then  copies seg A to seg B.

    //  Assumed MCLK 550kHz - 900kHz.

    //  //* Set Breakpoint on NOP in the Mainloop to avoid Stressing Flash *//

    //

    //               MSP430F149

    //            -----------------

    //        /|\|              XIN|-

    //         | |                 |

    //         --|RST          XOUT|-

    //           |                 |

    //

    //  M. Mitchell

    //  Texas Instruments Inc.

    //  Feb 2005

    //  Built with IAR Embedded Workbench Version: 3.21A

    //******************************************************************************

    #include  <msp430x16x.h>

    unsigned char  value;                                // 8-bit value to write to segment A

    //unsigned char  DataBuffer[128];

    // Function prototypes

    void  write_SegA (unsigned char value);

    void  copy_A2B (void);

    void main(void)

    {

     WDTCTL = WDTPW + WDTHOLD;                 // Stop watchdog timer

     FCTL2 = FWKEY + FSSEL0 + FN0;             // MCLK/2 for Flash Timing Generator

     value = 0;                                // Initialize value

     while(1)                                  // Repeat forever

     {

       write_SegA(value++);                    // Write segment A, increment value

       copy_A2B();                             // Copy segment A to B

       _NOP();                                 // SET BREAKPOINT HERE

     }

    }

    void write_SegA (unsigned char value)

    {

     unsigned char *Flash_ptr;                          // Flash pointer

     unsigned int i;

    //unsigned char *Flash_ptr2;                          // Flash pointer

     Flash_ptr = (unsigned char *) 0x1080;              // Initialize Flash pointer

     FCTL1 = FWKEY + ERASE;                    // Set Erase bit

     FCTL3 = FWKEY;                            // Clear Lock bit

     *Flash_ptr = 0;                           // Dummy write to erase Flash segment

     FCTL1 = FWKEY + WRT;                      // Set WRT bit for write operation

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

     {

       *Flash_ptr++ = value;                   // Write value to flash

     }                  

     FCTL1 = FWKEY;                            // Clear WRT bit

     FCTL3 = FWKEY + LOCK;                     // Set LOCK bit

    }

    //无法正常实现以下部分程序功能,不知道是不是编程软件原因

    void copy_A2B (void)

    {

     unsigned char *Flash_ptrA;                         // Segment A pointer

     unsigned char *Flash_ptrB;                         // Segment B pointer

     unsigned int i;

     Flash_ptrA = (unsigned char *) 0x1080;             // Initialize Flash segment A pointer

     Flash_ptrB = (unsigned char *) 0x1000;             // Initialize Flash segment B pointer

     FCTL1 = FWKEY + ERASE;                    // Set Erase bit

     FCTL3 = FWKEY;                            // Clear Lock bit

     *Flash_ptrB = 0;                          // Dummy write to erase Flash segment B

     FCTL1 = FWKEY + WRT;                      // Set WRT bit for write operation

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

     {

       *Flash_ptrB++ = *Flash_ptrA++;

       //DataBuffer[i] = *Flash_ptrA++;

       //*Flash_ptrB++ = DataBuffer[i];           // Copy value segment A to segment B

     }

     FCTL1 = FWKEY;                            // Clear WRT bit

     FCTL3 = FWKEY + LOCK;                     // Set LOCK bit

    }

  • 中午休息,简单分享一下MSP430单片机的使用感受。

    430系列应该说是近些年来比较受欢迎的单片机,在国内的普及也非常快。记得本科时,学习MCU是从51系列开始的,51单片机作为入门级的单片机,确实为进入MCU世界做了一个很好的铺垫,而后来,在具体的项目开发中,实际投入使用的却是430。MSP430的超低功耗、集成度和价格在市场上都是极具竞争力的,在各种终端设备和便携式电子产品的研发中具有得天独厚的优势。同时,TI的430系列紧密联系高校,在各种教学课程和电子设计竞赛中,都有它的身影。这也为430系列的产品推广做了很好的铺垫。当年在参加电赛的时候,得益于TI的430免费样片,省去了很多资费,在此也感谢TI对高校研究的支持。

    另外,430芯片的模块化结构也让我们在实际的使用中更加得心应手,能够在不同的应用领域灵活选用最合适的芯片类型,同时减去了重新学习的过程,可以说具有很高的效率,这一点,也是其他系列单片机所不能比及的。

    另外,我的一个感受是MSP430正在逐渐向着高集成度发展,其“单片作战”能力正在快速加强,比如近几年出的MSP430f5438单片机(我本科时第一个DIY的开发板的核心芯片,所以对它情有独钟...呵呵),其片上资源及其丰富,而且主频高达20M,可以说足以满足大部分中低端的市场需求,也可以摆脱以往的“我很省饭,但我也不很能干”的帽子....只是感觉其价格稍高,在这个价格段恐怕无法和ARM7系列相竞争。

    总之,这么多年,用430很顺手,希望日后能用更多TI的优秀产品。

  • 我算是TI MCU的老用户了,用的主要是C2000系类的MCU(之前一直叫DSP的,前几年将C2000系类改为MCU),从2808、2812,到28335,再到现在的28346。这里也和大家分享一下我使用TI MCU的一些经验。

    ①使用

    目前,在实时控制领域,如:电力电子、电源、电气传动等等,就我所了解的大部分人使用的都是TI的MCU。这其中的原因很多,就我而言主要是实验室一直用的TI的MCU,所以也就……。但用了这么久之后,我觉得TI的MCU用起来要比其他的厂商的同等MCU要更加的强大,使用起来也更加的方便。强大在于它有更多更为丰富、灵活的外设,使得CPU的负担大为减弱;方便在于TI提供的设计文档和资料要更加的全面,从外设文档到软、硬件资料。

    ②硬件设计

    在硬件设计方面,针对每一款MCU TI基本都提供了相应的硬件设计参考和文档,以28335为例,就有《TMS320F2833x 参考设计》,里面包含了设计电路,以及OrCAD的图,同样像《Designing Analog Interface with 28xx ADC》都是很值得参考硬件文档。对于有些芯片你可能不能直接找到像28335这样的参考设计,如:28346,但是不用担心,你还可以从TI官方的开发板、评估板上获取你所需要的硬件设计电路,像28346就有《Delfino C28346 DIM168 ControlCARD》。所有这些资料都不难找,你可以在相应芯片的的一个网页上全部获得,只要你细心总可以找到需要的资料。

    ③软件设计

    在软件上,TI对每一款芯片都提供例程,如《C2834x C/C++ 头文件和外设示例 》,这个我想大家都懂得,就不多说了。但是有一点需要提醒的就是有时候例程里面的代码也不一定全对,也有一些小的bug,所以写代码的时候自己要小心。

    举个bug的例子:

    在《C2833x C2823x C C++ 头文件和外设示例》--->DSP2833x_SysCtrl.c--->InitPeripheralClocks()中有几句代码:

      // XCLKOUT to SYSCLKOUT ratio.  By default XCLKOUT = 1/4 SYSCLKOUT

      // XTIMCLK = SYSCLKOUT/2

      XintfRegs.XINTCNF2.bit.XTIMCLK = 1;

      // XCLKOUT = XTIMCLK/2

      XintfRegs.XINTCNF2.bit.CLKMODE = 1;

      // Enable XCLKOUT

      XintfRegs.XINTCNF2.bit.CLKOFF = 0;

    如果你想将XCLKOUT关掉,很正常的在这里令XintfRegs.XINTCNF2.bit.CLKOFF = 1 即可,但是在例程中你会发现,你改过之后XCLKOUT还是会输出,没有被关掉。导致这样的原因就是这几句话前面还差了一条语句就是:

    SysCtrlRegs.PCLKCR3.bit.XINTFENCLK = 1;     // XTIMCLK

    如果不讲XINTF的时钟打开,对外设寄存器的操作是不会有效的。而例程中刚好将时钟开启的语句放到了配置外设寄存器的后面。

    希望上面所写的这样对大家有所帮助。

  • 说说自己和Ti,我2004年大学毕业,到一家公司开始了职业之旅。公司要上一个全新的双轴伺服项目,参考国外方案,选择数字化控制,由我咨询并确定采用F2812DSP。于是开始了DSP的使用开端,自己读英文资料,参考电路,设计了电路板,那时候清华出版社张卫宁编的参考手册还没出来,春节的时候才出了上册。还好电路板基本设计成功,借助Ti的头文件和例子,一步一步实现了DSP的基本功能,如IO、SCI、SPI(装订FPGA)、AD等。然后开始出差做整个系统调试,一塌糊地。一个月后,回到公司,开始从基础调试。此处省略……

    终于在解决完一切的基础问题后,系统可以运行了,到用户做实验,也得到了用户的认可。

    之后,F2812在这个方面的项目有了广泛应用,并且还应用的其它项目中,因为其当时运算速度还是比较快的。

    可以说,Ti的帮助,尤其是头文件和例程,对项目成功起了很大作用,非常感谢。

  • 总结一下,我以前用过的MSP430单片机的经验,差不多就这些。

    N年前的1.21/1.26版本,还是现在的3.10/3.40版本,IAR一直是我用的最多的一个编译/调试器,玩MSP430不可能不接触到这个 那我就以IAR调试为例来说说了咯

    原始级 问题,一般是刚开始入门的哥们姐们要遇到的问题

    1, 接上仿真器,发现不能下载,这个问题想必大家都有遇到过,IAR提示找不到目标!??

       可能的原因:  A 并口驱动能力不足,在电脑的BIOS界面下设置成ECP或者       ECP+EPP模式

                         B JTAG线太长,一般超过20CM不推荐,而且这个线最好不要交叉缠绕,会影响实时在线调试

                         C 你的负载太大,一般功耗相对比较大,电流超过20MA以上的板子,建议用外接电源,要不光靠并口那点驱动能力,那MCU的电压就要被拉低到不能写FLASH了,呵呵

    2, 程序下载到一半,突然告警并报错,说某某地址写不进去!??倒~~我开始也以为是FLASH被写坏了,呵呵,其实MSP430的FLSH没这么脆弱

      可能的原因:  A 芯片的复位电路引起的,在写FLASH的时候,会造成系统电压的一些波动,可能导致芯片复位,而为什么都是写到这个地址才错,那是IAR的问题,改用BSL再烧一边,就可以克服了

                        B 芯片有可能死机了,给断电,拔掉JTAG没,稍后再试,一般没有问题

                        C 如果都不是上述的方法能解决的,告诉你一个更酷的办法,给芯片上电,电压=3.6V,重新写一次,一定OK.为什么,写不进FLASH主要是F1XX系列的写FLASH电压不能低于2.7V,一般2.5V以下才不能真正工作,因此用3.6V电压,什么样的片子都能写回来(BTW,到现在为止,我还没写坏过一片MSP430的FLASH)

    3, 关于3.40以上版本的仿真器设置问题.

    说实在的,真正开发起来,我都不太愿意随便换IAR的版本,有些语法不兼容,有些设置不一样,不花点时间开 WHAT'S NEW,就要到BBS上去发贴了,呵呵

    最近装了3.40的 限制版,一路NEXT,好象没什么特别的地方,装好后发现芯片的选择余地多了很多,包括了F2XX,N多种类,哈哈再上硬件FET接着跑个DEMO看看,居然不成,报错!!

    原来:  在仿真栏目里选好 FET 硬件仿真以后,还有一项是访真器的选择,我倒~

    没仔细看的哥们姐们一定纳闷,为啥还要搞个 LPT || J-LINK || TI-USB ,更滑稽的是IAR居然认为现在大伙都有米买USB的FET,默认选项是 TI-USB,那就是这个问题咯,改成 LPT(并口FET) 就完事了。

  • 关于430,本人有如下一些体会,和大家分享:

    1.系统时钟问题:

    系统默认使用DCO,使用外部高速晶振XT2时必须自己开启XT2,并延时50us等待XT2起振,然后手工清除IFG1中的OFIFG位!!!!一定要注意操作顺序:打开XT2->等待XT2稳定->切换系统时钟为XT2

    若后面两步操作反了,在通常情况下不会出现问题,但是在电压不稳MCU频繁复位的情况下,非常容易造成MCU死掉,只能掉电后重新上电才能可靠复位。

    2.早期版本的IAR开发环境必须在Project->Option->C-Spy中选择对应器件的DDF文件,否则调试时无SFR窗口。

    3.在写Flash期间,一定要关闭中断,此时CPU无法执行程序

    4.调试的时候,不要选中"Release JTAG on Go"

    5.在调试时,需要关闭看门狗,否则在打开看门狗的情况下,每当执行到断点,程序将会跳转到入口点从头执行。或者,暂停运行或停止到断点处时,当需要继续运行时,程序不再执行,而是需要使用“同步JTAG”才能继续运行(从头运行?)

    6. IAR EWB标识符是区分大小写的

    7. 结构变量内部存在对齐要求,通常按照2个字节的位置对齐,在"C/EC++ Compiler Reference Guide"的P93又如下例子:

    struct {

    short s; /* stored in byte 0 and 1 */

    char c; /* stored in byte 2 */

    long l; /* stored in byte 4, 5, 6, and 7 */

    char c2; /* stored in byte 8 */

    } s;

    sizeof(s) 为10,而不是8

    可以使用#pragma pack来改变这种对齐方式,但是会导致,这个结构只能按字节方式存取

    8. MSP430 IAR C/EC++ Compiler支持两个运行库

       1. IAR CLIB : 主要用于8或16为处理器,不完全兼容ISO/ANSI C,也不完全支持IEEE 754浮点数,不支持Embedded C++.

       2. IAR CLIB : 支持ISO/ANSI C和Embedded C++.

    9. cstartup的定制

    (1). 在__low_level_init()中添加代码。该函数可以用来初始化I/O寄存器,并决定数据段是否在cstartup被初始化。文件430srcliblowin

    it.c给出了框架,copy到项目目录中使用,文件中有一定的使用说明。

    (2) 若__low_level_init()中添加代码不能满足要求,则把430srclibcstartup.s43拷贝到自己的工作目录,修改所需代码;然后在将该文

    件添加到项目,在项目选型的XLINK的include页下选择Ignore CSTARTUP in library即可。

    10. 使用#include "io430x14x.h"和#include "in430.h"来替代#include

    可以使用定义的位变量

    可以使用以下方式定义位变量,但是编译器最终还是转换为字节操作:

    struct

    {

    unsigned char WDTIE : 1;

    unsigned char OFIE : 1;

    unsigned char : 2;

    unsigned char NMIIE : 1;

    unsigned char ACCVIE : 1;

    unsigned char URXIE0 : 1;

    unsigned char UTXIE0 : 1;

    } IE1_bit;

    不推荐使用bitfields,效率很低

    11. 数组的索引值用int型效率最高,char型也好略低

    数组类型:char型数组效率最高,

    其他类型的数组在索引时,都采用了乘法

  •     说明:Altera公司的FPGA--DE0开发板与MSP430单片机之间实现SPI通信。MSP430具体型号为MSP430F247。

    //以下是MSP430处理的部分,具体解释已附在程序之中,如有疑问或有兴趣交流者,欢迎邮件至:shachangdianbing@126.com
    int main( void )
    {
      // Stop watchdog timer to prevent time out reset
        WDTCTL = WDTPW + WDTHOLD;
        
        DCOCTL = DCO0 + DCO1 + DCO2;
        BCSCTL1 = RSEL0 + RSEL1 + RSEL2 + RSEL3;
        
        key_value = 0xff;   //防止数据偏差,先赋初值
      
        P1IES |= BIT3;                //选择下降沿触发
        P1IE  |= BIT3;                 //打开中断允许
        P1IFG=0;                    //P1IES的切换可能使P1IFG置位,需清除
        lcd_initial();
        LCD_Delay(10);                 //液晶准备
        
        P3DIR |= BIT4;                 //设置发送从机主机标志,有按键就置高
        P3OUT &=~BIT4;
        P3SEL |= 0x0E;                  // P3.3,2,1 option select
        UCB0CTL1 = UCSWRST;              // 配置模式
        UCB0CTL0 |= UCCKPH+UCSYNC+UCMSB; //3线模式,MSB
        UCB0CTL1 &= ~UCSWRST;            // 通信初始化
        IE2 |= UCB0RXIE;                //接受中断开启
        
        _EINT();   //开总中断允许
        
        disp_chn(0,2,0);                 //输入电压:  V
        disp_chn(16,2,2);
        disp_chn(32,2,3);
        disp_chn(48,2,4);
        disp_word(64,2,58);
        disp_word(96,2,46);
        disp_word(120,2,86);
      
        disp_chn(0,4,0);                 //输出电压:   V
        disp_chn(16,4,1);
        disp_chn(32,4,3);
        disp_chn(48,4,4);
        disp_word(64,4,58);
        disp_word(96,4,46);
        disp_word(120,4,86);
      
        disp_chn(0,6,0);                //输出电流:  A
        disp_chn(16,6,2);
        disp_chn(32,6,3);
        disp_chn(48,6,5);
        disp_word(64,6,58);
        disp_word(96,6,46);
        disp_word(120,6,65);
     
        disp_chn(0,0,6);                //占空比:  %
        disp_chn(16,0,7);
        disp_chn(32,0,8);
        disp_word(48,0,58);
        disp_word(96,0,46);
        disp_word(120,0,37);
       
        while(1)
        {
          delay();
          
          P3OUT |= BIT4;             //刷新各种数据
          while(!(IFG2 & UCB0TXIFG));
          UCB0TXBUF = 0x20;
          P3OUT &=~BIT4; 
          middelay();
          disp_word(102,6,spi_in/10 + 48);
          disp_word(112,6,spi_in%10 + 48);
          
          
          P3OUT |= BIT4;
          while(!(IFG2 & UCB0TXIFG));
          UCB0TXBUF = 0x21;
          P3OUT &=~BIT4;
          middelay();
          disp_word(80,0,spi_in/10 + 48);
          disp_word(88,0,spi_in%10 + 48);
         
          P3OUT |= BIT4;
          while(!(IFG2 & UCB0TXIFG));
          UCB0TXBUF = 0x22;
          P3OUT &=~BIT4;
          middelay();
          disp_word(104,0,spi_in/10 + 48);
          disp_word(112,0,spi_in%10 + 48);
         
         
          P3OUT |= BIT4;
          while(!(IFG2 & UCB0TXIFG));
          UCB0TXBUF = 0x23;
          P3OUT &=~BIT4;
          middelay();
          disp_word(80,2,spi_in/10 + 48);
          disp_word(88,2,spi_in%10 + 48);
           
          P3OUT |= BIT4;
          while(!(IFG2 & UCB0TXIFG));
          UCB0TXBUF = 0x24;
          P3OUT &=~BIT4;
          middelay();
          disp_word(104,2,spi_in/10 + 48);
          disp_word(112,2,spi_in%10 + 48);
              
          P3OUT |= BIT4;
          while(!(IFG2 & UCB0TXIFG));
          UCB0TXBUF = 0x25;
          P3OUT &=~BIT4;
          middelay();
          disp_word(80,4,spi_in/10 + 48);
          disp_word(88,4,spi_in%10 + 48);
          
          P3OUT |= BIT4;
          while(!(IFG2 & UCB0TXIFG));
          UCB0TXBUF = 0x26;
          P3OUT &=~BIT4;
          middelay();
          disp_word(104,4,spi_in/10 + 48);
          disp_word(112,4,spi_in%10 + 48);
          
          P3OUT |= BIT4;
          while(!(IFG2 & UCB0TXIFG));
          UCB0TXBUF = 0x27;
          P3OUT &=~BIT4;
          middelay();
          disp_word(80,6,spi_in/10 + 48);
          disp_word(88,6,spi_in%10 + 48);
        
          delay();
          delay();
          delay();
       }
    }
    #pragma vector=PORT1_VECTOR
    __interrupt void key_int(void)
    {
      P1IFG = 0;  
      key_value = read(CMD_READ);        //取键值
      P3OUT |= BIT4;                             //产生按下信号
      while(!(IFG2 & UCB0TXIFG));          //等待输出寄存器准备好
      UCB0TXBUF = key_value;              //发送键值
      P3OUT &=~BIT4; 
    }
    #pragma vector=USCIAB0RX_VECTOR
    __interrupt void spi_recei(void)
    {
      while (!(IFG2 & UCB0RXIFG));        //等待接受寄存器
      spi_in = UCB0RXBUF;                   //接受
    }
    注意事项及经验教训:

    (1)每次写程序都要项目设置,当硬件仿真是,才能下载程序到板子里面去
    (2)有一段时间一直在检查一个错误,调试发现总是进不了中断,然后去检测I/O口数据,往I/O口送入特定信号,仍然调试发现进不了中断,最后才猛然发现,竟然是忘记了打开总中断,虽然使用430也一年多了,但也免不了犯些低级错误,可能是仍是学生的缘故吧,希望在大学后两年能更进一步的熟悉MSP430的使用。

    (3)请注意引脚连接,以及确定FPGA方面的引脚分配正确,有时候不一定是430这边的问题,FPGA方面也要注意。
    (4)使用430这么长时间以来,一直很喜欢这款单片机,功耗、性能、性价比方面都比较好,而且重要的是技术支持比较雄厚,学习资料比较多,可以较容易的入手,大快人心。

  • MSP430的AD12使用灵活,功能强大.我在学习的过程中特别总结了一下,分享给大家.

    1.AD12(12路输入通道(8路外部输入通道,4路内部输入通道),4种模式)

    (1)寄存器:

    A.转换控制:ADC12CTL0、ADC12CTRL1

    B.中断控制:ADC12IFG  、 ADC12IE  、ADC12IV

    C存储控制类:ADC12MCTL0 — ADC12MCTL15(8位寄存器,每个寄存器对应于一个ADCMEM12x,定义参考电压和通道)

    D.存储器类:ADC12MEM0 — ADC12MEM15

    (2)四种工作模式

    A.单通道单次转换

    B.单通道多次转换

    C.多通道(序列)单次转换

    D.多通道(序列)多次转换

    (3)ADC12CTL1有两个和时钟相关的设置:

    A.SHS:(0-4)采样输入信号源选择控制位.AD采样时钟.

    B.ADC12SSEL:(0-3) ADC12内核时钟. 

    特别注意二者的区别.

    (4)ADC12在AD转换中完全是自动完成的,所以在多次转换中大多在中断处理程序中处理.

    在学习中多练习是必要的,如下是单通道单次转换的例子.不同的工作模式需要设置不同的工作标志位(0-3).

    /*

    MSP430

    ADC12 单通道单次转换

    */

    #include <MSP430x13x.h>

    #define ADCMEM ((int *)0x0140)

    void Init(void)

    {

     WDTCTL = WDTPW + WDTHOLD ;

     /*ADC12 Setting*/

     P6SEL = 0xFF;

     ADC12CTL0 &= ~0x02 ;          //禁止转换

     ADC12MCTL0 = 0x00;            

     ADC12MCTL1 = 0x8A;

     ADC12CTL1 = 0x0202;

     ADC12CTL0 = 0x0010 + SHT0_8;

     ADC12CTL0 |= 0X02;            //使能ADC转换

    }

    //interrupt[ADC_VECTOR] void ADC12(void) ;

    //unsigned int Result ;

    int main( void )

    {

     unsigned int i ;

     unsigned int j;

     unsigned int Result[2];

     Init();

     while(1)

     {

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

       {

         ADC12CTL0 |= 0x01 ; //开始转换

         ADC12CTL1 &= ~0x01;

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

       }

       while((ADC12CTL1 & 0x01)==1);

       for(j = 0; j<2 ; j++)

       {

         Result[j] = ADCMEM[j];

       }

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

     }

     return 0;

    }

  •     我只是个业余的电子技术爱好者,没读大学什么的...下面我讲讲我初学ARM的一点点插曲~

        以前只会玩51单片机,一直觉得ARM比较困难,也没有使劲去学习。主要是过去的工作单位和电子行业关系不大,不用则荒废。后来转了工作,在一家电子设备研发制造公司,有机会接触电路设计和嵌入式软件设计这些领域,促使我也能更好的学习下去。

        第一次玩TI的cortex-m3单片机是因为我在公司一块废旧电路板上看到有颗LM3S102芯片,于是看着这个只有28个脚的ARM很是向往知道他的奥妙。于是打算拆下了做块板子来做做实验,学习一下。

        刚好那段时间在学Altium designer PCB设计的知识,于是兴冲冲的实际发挥一下,设计了一 块基于LM3S102的最小系统板,为了节省成本,只打了5cmX5cm大小的板子,很小,可称得上迷你板了。上面附带的外设都以IIC总线或SPI总线的方 式工作的。主要有RTC,EEROM,FLASH,AD,这几个芯片~其他什么的我觉得不是很需要,板子空间很有限,就没用了。所有输入输出口都以排针引 出,JTAG使用7针简化单排针,还带有两个排针母座,一个就特意方便我接插我的12864屏幕,一个就引出了iic和spi总线。方便连接外部芯片。
        板子发到工厂几天后就收到货了,心情很激动,第一次打PCB板,一眼看上去板子还不错。不过经过仔细的研究还是总结出了不少设计上的缺陷。不过没多大问题。我设计电路的时候,都是选了公司见得到的零件,所以,板子到了后一天就焊完了,不过没调试成功。
        起初就是一直连接不上JLINK,因为是特制的单排针jlink接口,所以我用万能板做了一个小板子转接,试了好久,发现只在SWD模式下连接到一点,但都不能下载程序。后来仔细检查才发现转接板两个引脚间短路。。。
        修复转接板后再试,似乎有点好转,但仍然连接不上,后来回家试的时候就可以了,发现是公司的Jlink-arm-flash软件版本不合适。
        能下载程序了~高兴一把,但是后来试了好久,最基本的闪灯例程都出不来,程序改了看了,都找不出有什么原因,难道是芯片坏了?不可能呀,能Jlink连接 芯片,应该没事的。。。后来想到会不会是晶振没起振,于是去查了下晶振部分代码,直接把晶振改为使用内部振荡器,程序下载进芯片后,果然出现了惊喜,灯开 始交替闪烁了。于是我估计外部晶振有什么问题或啥的。
        灯可以闪了,最基本的GPIO操作实验完成了。说明板子能用,芯片能用,高兴着。然后要做的试验就是驱动我的OLED显示屏,是标准12864点阵屏幕。不带字库。要自己写字模。也是搞了好久都不成,最后发现一个玄机。原来写端口函数我用的不对。写入数值的时候,我只是用了0,1这两个数来清零和置位,其实是错的。这两个数只能写 到端口的0引脚上。如果要对A端口的位3写1,应该在写端口函数的参数用1<<3,就是把这个1移动到位3。呵呵,现在已经成功操作液晶屏 了。
        不过最郁闷的事也发生在这。设计的母座方向和液晶插针方向不配合了,当时没想到这一点,翻转了~我做实验将就玩玩也不碍事,不过还是一个缺憾。毕竟是第一次设计PCB,以后就要有经验了。

        在调试IIC的ads1110时,我是用通用GPIO模拟总线方式,主要是因为对这款ARM芯片内部硬件IIC总线功能不熟悉,所以觉得直接用GPIO更容易完成读AD试验。不过我做这个试验时,也是一波三折。我利用上面做的12864驱动试验的成功经验,跟AD采集数据结合,将AD上采集的数据显示在我的OLED显示屏上。开始测试了很多遍,感觉一点效果也没有,我在IIC读数据函数里放置陷阱测试,发现是在寻址时无法得到芯片的回应。经过仔细测量,才发现由MCU到AD芯片的IIC总线有一条没有拉铜箔。怎么会有这种事?我仔细的翻看了下我的电路设计原图,恍然大悟,才发现是网络号没有放得到位,放偏了点,结果看起来好像是一起了,实际还没有连通网络。失败。。。要吸取教训...
        飞线连接上之后,没有预料的成功。于是实在无可奈何,也找不到什么提示资料。过了几天,我好像突然想到一个问题,于是赶紧测试一下。果然成功了。原来呀,用惯了51,一时没有转变过来,ARM这个芯片,管脚读和写的状态需要切换,我没有注意这一点的不同,导致无法读取总线电平变化。最终,我还是懂了~

        虽然在学习和试验中遇到各种小问题,也耗费了很多时间去琢磨,但最终学到了不少东西,因此感觉快乐。在脑子了对ARM也有了初步的认识,开始觉得ARM也没有曾经想象的那么难那么难。今后还要继续学习。

  • 五六月份调试一个使用MSP430F2132作为主控单片机的系统,在ADC操作上遇到了些问题,现将过程分享出来,希望对初学者能有所帮助。

    1. 使用ADC10模块测量电源电压,参考电压使用内部的2.5V,时钟源ADC10OSC,不分频,通道选择11,即(VCC – VSS) / 2,参考TI的示例程序,编写并调试出相关功能代码如下:
    void vcccheck(void)
    {
      ADC10CTL0 = SREF_1 + ADC10SHT_2 + REFON + ADC10ON + REF2_5V;
     
      ADC10CTL1 = INCH_11;

      ADC10CTL0 |= ENC + ADC10SC;

      soft_delay_us(1000);

      while(!(ADC10CTL0 & ADC10IFG))
      {
        __no_operation();
      }

      if( ADC10MEM < 614 )
      {
        ...; //自定义处理过程
      }
      else
      {
        ...; //自定义处理过程
      }

      ADC10CTL0 = 0;      //停止ADC
    }

    2. 按上述程序调试,得到ADC10MEM测量值,但最后测量整个线路板的静态(LPM3)功耗时却发现比设计指标多了几百微安。怀疑是外围电路引起的,因为不敢怀疑430的功耗指标,于是用硬件和软件的方法对外围电路进行排除法测试,包括从PCB上断开单片机正电源路径,实验结果可以排除焊接及外围电路带来超标功耗的可能性。这时开始怀疑是不是自己哪里的设置不对,请教代理商的技术支持,咨询可能是什么部分引起的功耗,他们建议拿空板只焊单片机来进行区分是单片机引起还是外围电路引起的。我嫌麻烦,因为再去焊那QFN封装很麻烦,而且手头没有空板了。于是绞尽脑汁分析自己的电路,除了单片机自身功耗,以及I/O口在LPM3状态时输出高低电平或输入高电平或许是问题源头,其它地方从理论上看不可能带来额外功耗。没办法,动手吧。把外围电路断开,并按技术支持的建议,将输出都置为低电平输出或输入状态。再测试功耗,基本还是那么大!改分析程序吧,把原来休眠后的看门狗关掉,中断关掉,还是那么大,要奔溃了!打开芯片数据手册,将有被使用的功能模块的用法逐一再研读并实验,最后到了ADC10这一块了,细读ADC10CTL0寄存器的说明,突然发现可能是最后一句停止ADC没起作用,因为这个寄存器比较特殊,除了末四位,其它位能被修改是有前提条件的,即ENC=0。发现新大陆,当初编程时没太注意这一点,而且示例程序中并不说明这些。于是乎,在最后一句之前再加上一句“ADC10CTL0 &= ~ENC;”,再试,功耗一下降下去几百微安,基本接近设计指标,还原其它为了调试而修改的外围电路和I/O口状态,基本没影响,也就是说此ADC10模块在不进行转换操作时,功耗有几百微安。神哪,问题总算找到了,后悔当初不仔细研究数据手册啊!

    3. 总结调试过程,除了上述寄存器的修改方法,另得到几个结论:I/O口的漏电是很小的,比如在休眠状态,即使某个I/O保持高电平输出状态来控制外部的PNP三极管处于截止状态,这样也并不影响低功耗;430单片机的低功耗指标参数是值得信赖的,除非你的单片机已经损坏了;

  • F28335的位域和寄存器结构学习

    -----------------------------------------------

    以前一直在使用C5000系列的DSP,具体型号为VC5509A。不久前也接触了C2000系列的28335。在学习这款DSP的过程中,感觉和C55X差别不少。特别是在编程方面,两者对底层寄存器的操作方式有很大区别。F28335拥有很丰富的外设资源,这也就说明了它必然有比较复杂的存储单元映射和中断管理体系。关于存储单元映射,TI提供了C/C++ Header files文件来管理,这个和CSL有些类似,但和CSL并不完全相同。首先在CSL使用最多的是宏伪指令,而在F28335中使用最多的是位域和寄存器文件结构体。同CSL相比,有利也有弊。在下面会详细列出两者的优缺点。这是我认为的最有用的一块,它为F28335提供了一个硬件抽象层,使得编程者无需去记忆大量寄存器名称。而且它提供了一个很好的编程规范,是以后编程很好的参考。所以花了一番功夫研究位域和寄存器文件结构体。

    现将其中重要的部分描述如下:

    1、宏与位域和寄存器结构优缺点的对比

    传统的#define宏提供了地址编号或者是指向寄存器地址的指针。

    这样做的优点是:1、简单,快,很容易通过键盘敲出。

    2、变量名和寄存器名一致,容易记忆。

    缺点是:1、具体位不容易获取,必须生成掩码来对某个位操作。

    2、不能够在CCSwatch window中方便的显示某些位的值。

    3、宏不能够利用CCS的自动完成功能。

    4、宏不能对相同外设重复使用。

    位域和寄存器结构体的优点如下:

    1TI提供,无需自己编写,规范性好。

    2、容易读、写、升级,效率高。

    3、很好的利用了CCS的自动完成功能。

    4、可以在CCS的观察窗口中查看具体位的值。

    2、实现位域和寄存器文件结构体的具体步骤(以SCI外设为例)

    1)、定义一个寄存器文件结构体,SCI外设的寄存器在结构体中按实际的地址由低向高依次列出。

    /********************************************************************

    * SCI header file

    * Defines a register file structure for the SCI peripheral

    ********************************************************************/

    #define    Uint16    unsigned int

    #define    Uint32    unsigned long

    struct SCI_REGS {

    Uint16    SCICCR_REG      SCICCR;             // Communications control register

    Uint16    SCICTL1_REG     SCICTL1;             // Control register 1

    Uint16                                SCIHBAUD;         // Baud rate (high) register

    Uint16                                SCILBAUD;         // Baud rate (low) register

    Uint16    SCICTL2_REG     SCICTL2;             // Control register 2

    Uint16  SCIRXST_REG    SCIRXST;            // Receive status register

    Uint16                               SCIRXEMU;               // Receive emulation buffer register

    Uint16  SCIRXBUF_REG SCIRXBUF;         // Receive data buffer

    Uint16                               rsvd1;                   // reserved

    Uint16                               SCITXBUF;          // Transmit data buffer

    Uint16  SCIFFTX_REG     SCIFFTX;            // FIFO transmit register

    Uint16  SCIFFRX_REG    SCIFFRX;            // FIFO receive register

    Uint16  SCIFFCT_REG     SCIFFCT;             // FIFO control register

    Uint16                               rsvd2;                   // reserved

    Uint16                               rsvd3;                   // reserved

    Uint16  SCIPRI_REG        SCIPRI;                      // FIFO Priority control

    };

    2)、上面的定义本身并没有建立任何的变量,只是定义了一个结构体,而并没有实例化。下面即定义了具体的变量。注意在这里使用了volatile关键字,它在这里的作用很重要,这使得编译器不会做一些错误的优化。

    /********************************************************************

    * Source file using register-file structures

    * Create a variable for each of the SCI register files

    ********************************************************************/

    volatile    struct      SCI_REGS    SciaRegs;

    volatile    struct      SCI_REGS    ScibRegs;

    3)、利用DATA_SECTION Pragma,将寄存器文件结构体变量分配到特殊的数据段中。如果不使用这条指令,那么定义的寄存器文件结构体变量默认是被分配在.ebss或者.bss段的,但通过使用DATA_SECTION Pragma指令,编译器会将其放在了一个特殊的数据段中。具体实现如下:

    /********************************************************************

    * Assign variables to data sections using the #pragma compiler statement

    * C and C++ use different forms of the #pragma statement

    * When compiling a C++ program, the compiler will define __cplusplus automatically

    ********************************************************************/

    //----------------------------------------

    #ifdef      __cplusplus

    #pragma  DATA_SECTION("SciaRegsFile")

    #else

    #pragma  DATA_SECTION(SciaRegs,"SciaRegsFile");

    #endif

    volatile    struct      SCI_REGS    SciaRegs;

    //----------------------------------------

    #ifdef     __cplusplus

    #pragma DATA_SECTION("ScibRegsFile")

    #else

    #pragma DATA_SECTION(ScibRegs,"ScibRegsFile");

    #endif

    volatile    struct      SCI_REGS    ScibRegs;

    通过上面的代码可以看到,定义的SciaRegs被分配到了SciaRegsFile段中,ScibRegs被分配到了ScibRegsFile段中。

    4)、上面只是将定义的寄存器结构体变量分配到了一个特殊的数据段中,通过cmd文件,可将其映射到实际的存储单元,进而和外设实际的存储器映射地址统一起来。实现如下:

    /********************************************************************

    * Memory linker .cmd file

    * Assign the SCI register-file structures to the corresponding memory

    ********************************************************************/

    MEMORY

    {

    ...

    PAGE 1:

    SCIA : origin = 0x007050, length = 0x000010 /* SCI-A registers */

    SCIB : origin = 0x007750, length = 0x000010 /* SCI-B registers */

    ...

    }

    SECTIONS

    {

    ...

    SciaRegsFile : > SCIA, PAGE = 1

    ScibRegsFile : > SCIB, PAGE = 1

    ...

    }

    5)、添加位域定义。

    获取寄存器中特定的位经常是很有用的,位域的定义就提供了这种方便性;但是与此同时位域也缺乏硬件平台之间的可移植性。在位域的定义中,最低位,也就是0位,是寄存器中的第一个位域;位域不能超过寄存器的位数,最多为16位。

    /********************************************************************

    * SCI header file

    ********************************************************************/

    //----------------------------------------------------------

    // SCICCR communication control register bit definitions:

    //

    struct      SCICCR_BITS {                 // bit description

    Uint16    SCICHAR:3;                       // 2:0 Character length control

    Uint16    ADDRIDLE_MODE:1;        // 3 ADDR/IDLE Mode control

    Uint16    LOOPBKENA:1;                 // 4 Loop Back enable

    Uint16    PARITYENA:1;                  // 5 Parity enable

    Uint16    PARITY:1;                         // 6 Even or Odd Parity

    Uint16    STOPBITS:1;                      // 7 Number of Stop Bits

    Uint16    rsvd1:8;                              // 15:8 reserved

    };

    //-------------------------------------------

    // SCICTL1 control register 1 bit definitions:

    //

    struct SCICTL1_BITS {                            // bit description

    Uint16    RXENA:1;                          // 0 SCI receiver enable

    Uint16    TXENA:1;                          // 1 SCI transmitter enable

    Uint16    SLEEP:1;                           // 2 SCI sleep

    Uint16    TXWAKE:1;                       // 3 Transmitter wakeup method

    Uint16    rsvd:1;                                // 4 reserved

    Uint16    SWRESET:1;                      // 5 Software reset

    Uint16    RXERRINTENA:1;             // 6 Receive interrupt enable

    Uint16    rsvd1:9;                              // 15:7 reserved

    };

    在上面的定义中,使用了操作符“:”,用来说明位域的长度,即当前位域占几位。

    6)、使用联合体。除了能够方便的访问位域外,有时候也希望能够对寄存器整体访问,使用联合体能够实现这种操作。

    /********************************************************************

    * SCI header file

    ********************************************************************/

    union SCICCR_REG {

    Uint16                                all;

    struct      SCICCR_BITS      bit;

    };

    union SCICTL1_REG {

    Uint16                                all;

    struct      SCICTL1_BITS     bit;

    };

    7)、将添加位域后的寄存器结构体重新实现。

    /********************************************************************

    * SCI header file

    * Defines a register file structure for the SCI peripheral

    ********************************************************************/

    #define    Uint16    unsigned int

    #define    Uint32    unsigned long

    struct SCI_REGS {

    Uint16    SCICCR_REG      SCICCR;             // Communications control register

    Uint16    SCICTL1_REG     SCICTL1;             // Control register 1

    Uint16                                SCIHBAUD;         // Baud rate (high) register

    Uint16                                SCILBAUD;         // Baud rate (low) register

    Uint16    SCICTL2_REG     SCICTL2;             // Control register 2

    Uint16  SCIRXST_REG    SCIRXST;            // Receive status register

    Uint16                               SCIRXEMU;               // Receive emulation buffer register

    Uint16  SCIRXBUF_REG SCIRXBUF;         // Receive data buffer

    Uint16                               rsvd1;                   // reserved

    Uint16                               SCITXBUF;          // Transmit data buffer

    Uint16  SCIFFTX_REG     SCIFFTX;            // FIFO transmit register

    Uint16  SCIFFRX_REG    SCIFFRX;            // FIFO receive register

    Uint16  SCIFFCT_REG     SCIFFCT;             // FIFO control register

    Uint16                               rsvd2;                   // reserved

    Uint16                               rsvd3;                   // reserved

    Uint16  SCIPRI_REG        SCIPRI;                      // FIFO Priority control

    };

    3、进行“读-修改-写”操作时需要注意的寄存器,及其解决方案

    1、在“读-修改-写”操作时,硬件可能修改的寄存器。

    1)在需要清除PIEIFRx某个位的值的时候,需要借助CPU的中断来清除。这时将修改中断向量表,将对应的中断重新分配到一个假的ISR中,然后让CPU进入这个假的ISR,自动清除相应的位,然后再恢复中断向量表。

    2)当对GPxDAT进行操作时,由于GPxDAT反映的是引脚上的值,在对其连续-修改-操作时,由于读和写操作的时间不同,会得到不希望的结果。解决措施是:不通过GPxDAT改变引脚的值,而使用其他寄存器GPxSET/GPxCLEAR/GPxTOGGLE,由于这些寄存器只对具体的位操作,因而不会影响到其他的位。

    2、具有写1清除位的寄存器。

    例如TCR寄存器中的TIF位,当向其中写1的时候回将其清零。在读取它的值之前如果先要停止寄存器,就要对TSS位操作,这时就会发生一次“读-修改-写”操作。如果此时TIF1,经过这个操作后就会被清零,所以后面的质量永远也检测到TIF1。比如下面的例子:

    // Stop the CPU-Timer

    CpuTimer0Regs.TCR.bit.TSS = 1;              3F80C7 MOVW DP,#0x0030

    3F80C9 OR         @4,#0x0010

    // Check to see if TIF is set                        3F80CB TBIT      @4,#15

    if (CpuTimer0Regs.TCR.bit.TIF == 1)        3F80CC SBF       L1,NTC

    {                                                             3F80CD        NOP

    // TIF set, insert action here                       3F80CE L1:

    // NOP is only a place holder ....

    asm(" NOP");

    }

    解决的方法是使用一个虚拟的寄存器,在停止定时器时,对TIF位写0,这样就不会改变TIF的值了。示例代码如下:

    union TCR_REG shadowTCR;

    // Use a shadow register to stop the timer

    // and preserve TIF (write 1-to-clear bit)

    shadowTCR.all = CpuTimer0Regs.TCR.all;               3F80C7 MOVW DP,#0x0030

    shadowTCR.bit.TSS = 1;                                         3F80C9 MOV     AL,@4

    shadowTCR.bit.TIF = 0;                                          3F80CA        ORB      AL,#0x10

    CpuTimer0Regs.TCR.all = shadowTCR.all;               3F80CB MOVL   XAR5,#0x000C00

    3F80CD        AND      AL,@AL,#0x7FFF

    // Check the TIF flag                                               3F80CF MOV     *+XAR5[4],AL

    if(CpuTimer0Regs.TCR.bit.TIF == 1)                       3F80D0 TBIT      *+XAR5[4],#15

    {                                                                           3F80D1 SBF       L1,NTC

    // TIF set, insert action here                                     3F80D2 NOP

    // NOP is only a place holder                                   3F80D3 L1:

    asm(" NOP");

    }

    3、需要特定值的寄存器。

    在向WDCHK中的检查位写数的时候必须始终为101;否则就会被认为是不合法的,将复位器件。但是在读取的时候这几位始终为000;如果将这个值写回,那么就会造成器件的复位。解决方法是:在头文件中,不对WDCHK定义位域操作,这样就避免了对WDCHK-修改-操作,在对其操作时只有一个固定的写操作。示例代码如下:

    SysCtrlRegs.WDCR = 0x0068;

     

    F28335的程序来讲,它充分利用了位域和寄存器文件结构体,通过这种结构将众多的外设组织起来了,甚至中断向量表也是通过这种结构来实现的。

  • 以前公司在2812做电力监控和无功补偿方面的控制器,2812总体来说稳定性能还是相当不错的!这也是我第一次接触和使用TI公司的dsp,对DSP内部的资源有了更深的了解!但一直搞不懂这个配置文件,可否解答下?

    SECTIONS

    {

      PieVectTableFile : > PIE_VECT,   PAGE = 1

    /*** Peripheral Frame 0 Register Structures ***/

      DevEmuRegsFile    : > DEV_EMU,     PAGE = 1

      FlashRegsFile     : > FLASH_REGS,  PAGE = 1

      CsmRegsFile       : > CSM,         PAGE = 1

      XintfRegsFile     : > XINTF,       PAGE = 1

      CpuTimer0RegsFile : > CPU_TIMER0,  PAGE = 1  

      PieCtrlRegsFile   : > PIE_CTRL,    PAGE = 1      

    /*** Peripheral Frame 1 Register Structures ***/

      SysCtrlRegsFile   : > SYSTEM,      PAGE = 1

      SpiaRegsFile      : > SPIA,        PAGE = 1

      SciaRegsFile      : > SCIA,        PAGE = 1

      XIntruptRegsFile  : > XINTRUPT,    PAGE = 1

      GpioMuxRegsFile   : > GPIOMUX,     PAGE = 1

      GpioDataRegsFile  : > GPIODAT      PAGE = 1

      AdcRegsFile       : > ADC,         PAGE = 1

      EvaRegsFile       : > EVA,         PAGE = 1

      EvbRegsFile       : > EVB,         PAGE = 1

      ScibRegsFile      : > SCIB,        PAGE = 1

      McbspaRegsFile    : > MCBSPA,      PAGE = 1

    /*** Peripheral Frame 2 Register Structures ***/

      ECanaRegsFile     : > ECANA,       PAGE = 1

      ECanaLAMRegsFile  : > ECANA_LAM    PAGE = 1  

      ECanaMboxesFile   : > ECANA_MBOX   PAGE = 1

      ECanaMOTSRegsFile : > ECANA_MOTS   PAGE = 1

      ECanaMOTORegsFile : > ECANA_MOTO   PAGE = 1

    /*** Code Security Module Register Structures ***/

      CsmPwlFile        : > CSM_PWL,     PAGE = 1

    }

    /******************* end of file ************************/

  • 这段程序困扰我好久了,程序的功能是取出五个数据进行一个排序滤波算法,之后再进行一个线性化的过程,可是不知道为什么,最后的结果和我理论值相差得很远,程序如下:

    void calculateT(void)
    {
     unsigned char i;
     unsigned char j;
     unsigned int var;
     float temp;
     float tobj;
     unsigned int t;
     for(i = 0;i < 5;i++)   // 排序
     {
      for(j = i + 1;j <= 5;j++)
      {
       if(vobj[i] > vobj[j])
       {
        var = vobj[j];
        vobj[j] = vobj[i];
        vobj[i] = var;
       }
      }
     }
     temp = (vobj[1]+vobj[2]+vobj[3]+vobj[4])/4;
     temp = 5*temp*ess/65536/100;
     tobj = -2.89874*temp*temp*temp*temp*temp*temp + 56.25177*temp*temp*temp*temp*temp - 447.2467*temp*temp*temp*temp \
      + 1868.486*temp*temp*temp - 4352.225*temp*temp + 5705.39*temp - 2985.6;
     t = (int)(tobj);
     if (t>350)
      {
       P5DIR |= 0x10;           //P5.4
       P6OUT &=~ 0x02;           //GREEN
      }
     else
      
      {
       P5DIR &=~ 0x10;               //P5.4
       P6OUT |= 0x02;           //GREEN
      }
    }

    用的单片机是msp430f147的,编译环境iar4.2

  • 我第一次接触msp430系列的mcu是从申请到的第一块msp430f149开始的。以前只听说过这一款超低功耗的mcu,片内资源丰富,可是一直没开始学。卡到TI有免费的芯片,就希望从这里开始。 经过一个多月的学习和试验,已经能比较熟练运用了,这次全国电子设计竞赛,我就使用了msp430f169做了小车的题目,目前还在调试。

  • 以下是我在使用msp430单片机过程中的碰到的一些问题及解决方法:

    1、msp430在执行主程序之前默认会对将程序中定义的相关变量初始化为0,但当需要在程序中定义大型数组时,最好在数组前加__no__init,告诉编译器这个数组不需要进行初始化,否则可能因为初始化时间超过WDT而导致不断复位。我曾经在写过一个程序,需要定义两个1024长度 int型全局数组,也就是说总共占用4KB字节RAM,当时用的是msp430f2618,其RAM为8KB,按道理不应该出问题。不过当我把程序下到单片机里是,程序一直运行在main函数之前的一段引导区代码,无法进入到主程序中。在加了__no__init预编译说明后,问题得到解决。

    2、在调试程序过程中,如果发现某内存单元的数据无故被改变的时候,很可能是指针溢出引起的问题。在写单片机程序的时候我们可能会遇到三种类型的指针:(1)自己定义的指针(2)数组下标(3)某些起指针作用的SFR。我把指针比作是“既聪明又淘气的孩子”,聪明是因为,很多算法可以很容易用指针实现,淘气是因为一旦程序中指针出问题,非常难以察觉。我曾经写一个程序要用到DMA,在执行到某句代码时,发现有个完全不想管的变量被无故改变,当时想到可能是哪个指针溢出导致的,不过观察了程序中所有的指针变量和数组下标,都发现没问题。后来才发现是DMA的source address指针出问题了,此指针应该是递增,我设置成了递减,导致溢出。

    3、430总中断的控制位是状态寄存器内的GIE位(该位在SR寄存器内),该位在复位状态下,所有的可屏蔽中断都不会发生响应。可屏蔽中断又分为单中断源和多中断源的。单中断源的一般响应了中断服务程序中断标志位就自动清零,而多中断源的则要求查询某个寄存器后中断标志位才会清零。由于大多数人接触的第一款单片机通常是51,51单片机CPU在响应低优先级的中断程序过程中若有更高优先级的中断发生,单片机就会去执行高优先级,这个过程已经产生了中断嵌套。而430单片机则不同,如果在响应低优先级中断服务程序的时候,即使来了更高优先级的中断服务请求,430也会置之不理,直至低优先级中断服务程序执行完毕,才会去响应高优先级中断。这是因为430在响应中断程序的时候,总中断GIE是复位状态的,如果要产生类似51的中断嵌套,只能在中断函数内再次置位GIE位

    4、430的中断向量是FFE0H—FFFFH,一共32个字节也就是FLASH的最后一段,430的FLASH有大有小,但是最后地址肯定是FFFFH(大FLASH超过64K的除外)所以它们的起始地址是不一样的,而一般IAR默认编译都是把程序放在FLASH开始的位置(不包括信息段)。

    有个值得弄清楚的问题是:什么是中断向量?中断向量实际就是保存中断函数入口地址的存储单元空间。就像FFFEH+FFFFH这2个字节是复位中断向量,那么它存储的就是主函数在FLASH内的起始地址,假如主函数保存在以0x1100为起始地址的FLASH块内 ,那么你会发现FFFFH 内保存的是0x11, FFFE内保存的是0x00.其他什么TimerA,ADC12,所有的都一样。只是你每次写的程序长短不一,中断函数放的位置不一样。IAR编译器都会给你定好,然后在你用JTAG烧写程序的时候,把这个地址,烧写到相应的中断向量。因为中断函数所处地址可以由用户自定义,也可以让IAR自动编译,所以这个地址除了源代码开发人员知道,其他人是不知道的,BSL就是应用这32个字节的中断向量内的内容的特殊性设置的密码。但是有几个东西在430是不变的,就是触发中断的条件满足后,它到哪个地方去寻址中断服务函数的入口地址,是TI 在做430时就固化好,定死的。比方说上电复位的时候,它知道去FFFE,FFFF单元找地址,而不去FFE0,FFE2找地址,这个映射关系是430固化不变的。可有的时候你就是需要改变“中断向量”,这怎么办?430FLASH程序自升级里有时就会碰到这个问题,方法是在430原来默认的中断向量表内做一个跳转操作,同样以上电复位为例:

    ORG  0x2345

    PowerReset: mov.w  &0xFCFE,PC

    …………………………

    …………………………

    ORG  0xFFFE

    DW   PowerReset

    这样的话0xFCFE就相当是0xFFFE的映射了

  •    我是2011年8月8日收到TI发给我的免费样品(MSP430F169),当我初次看到它的时候就对它爱不释手。于是我迫不及待的为它设计了一个最小系统板和一小部分简单的外围应用电路。当我将一个管脚一个管脚地将它变成一个“小成品”的那一刻,我有着说不出来的心动。我仿佛看到了它那强大的“心脏”。

       由于我手上没有430的仿真器。所以,我特地为它设计了一个mini下载器(采用的是PL2303,适合没有并口的笔记本)。当一切的硬件条件已经具备,我开始测试了。但一切并不是一帆风顺的,我对软件做了一切排查之后,我确信是“开发板”出了问题。于是,我对板子进行了通电测试,这是我的万用表发挥了它强大的功能。经过一个上午系统的排查之后,我终于找到了问题所在,并最终解决了它。当我第一次把一小段测试程序顺利下载后,我感到一种幸福之感。

      然后,我就开始了我的“开发板”的系统学习过程。从流水灯、数码管、液晶,从系统时钟、中断、到定时器,每一个部分都学习都给我带来了无比的欢喜。现在我已经完成了板子的大部分模块的学习,从DS1302时钟、DS18B20温度采样到EEPROM、从I2C到SPI等总线模式的学习。每个模块化的学习都让我更加了解了MSP430,一个强大的MUC(在同类别MCU中)。

      是它、一款功能强大的处理器(MSP430F169)。它让我的暑假过得很精彩。感谢MSP430F169、感谢MY TI!

  •        最近正在用TI的MSP430做一款探测器,使用普通电池供电,要求能正常工作1年以上。所以在单片机选型的时候就自然而然想到了MSP430,它在低功耗方面的优势实在太明显!

       待规格确定后,原理图设计完,就该编写程序了。

       程序要实现的功能主要有两部分,其一是探测;其二是通信。使用汇编编写。

       写程序前当然要先设计流程图了,有了流程图就有了思路,调试改错以及将来维护都很方便。没有流程图的汇编程序是比较恐怖的,有一次我要改两年前的汇编程序,脑子都想成一堆浆糊了,就是想不起来当时为什么那么编写!悔呀!

       在编写程序过程中,遇到了一些有意思的事情:

    1、JMP指令只能在-511到+512字范围内跳转,如果想跳得更远些,就需要多个JMP指令接力了,呵呵,听说过烽火台点狼烟接力,看过田径跑步接力,现在程序跳转也玩接力了!

    2、通信时使用比较复杂的协议,需要判断输入引脚的电平,由于种种原因不能使用中断,所以选择了查询的方式,虽然设计时理论上查询可以足够快,但实际上会由于通信线的干扰而导致脉冲变窄,有漏掉脉冲的情况。后来不再查询引脚的电平,改为查询引脚中断标志,这样便解决了问题。

    3、16位单片机和8位单片机在写汇编程序时体会非常明显。因为对于16位单片机,必须时时刻刻想着我用的这个变量是16位的还是8位的,尤其是赋值、运算的地方,都是滋养bug的好地方。找bug是一件很辛苦的事情,为了少愁白几根黑发,能用C还是尽量用C吧。

    4、定义了个变量:    Temp DS16 1;

    然后对它操作,如清零: clr.w Temp; 有人喜欢写 clr.w &Temp;

    这两种写法都对,我知道它们对应的是两种不同的寻址方式,只是感觉很奇怪,为什么要这么设计?

    另外对寄存器的操作是不能用&的,是不是又是一个滋养bug的好地方?

    5、进入LPM3低功耗模式,功耗真的很低,不到1个uA,太强了!

       总之,MSP430单片机功能是非常强大的,我用到了它的片上Flash作EEPROM,非常方便;用它的Timer_A在连续工作模式下做定时器,非常方便。还用到了内部经过校准的1M振荡器,省了外接晶振。

  • 自己感觉用TI的产品有很长的一段时间了,一直感觉TI比其他公司更大方,资料也提供的更多,因此,感觉TI很亲切。到现在,我感觉TI也是做的最大的,在数字芯片方面更是摇摇领先。

    我和Ti接触是从利尔达开始的,那次去参加由利尔达和TI公司合办的MCUday的研讨会,送了一块TI的piccolo的开发板子,当时感觉很兴奋,就玩了一段时间,在玩的过程中,由于要找一些资料,所以进入了TI的官方网站做进一步的了解,后来还申请了一些芯片,感觉TI特别的号,不但提供芯片,还免费送过来,真的很人性化,我想这也是他为什么能做的这么大的原因吧。后来也申请使用了TI的其他产品,比如430等控制芯片,用起来非常的好,同时还用了TI的电源芯片,感觉也很不错,稳压稳的精度很高。

    后来,我又参加了几次TI的研讨会,最进的一次是还是参加利尔达和TI高的MCUDAY的研讨会,这次送了好几块板子,这下又要学的很长时间了,感觉没有其他的公司能比TI更让我信任的了,非常感谢他,同时也会继续关注。

    现在TI收购了刘明,在推出ARM系列,感觉也做的很好,希望以后能有跟多的研讨会和送一些更多的板子,其实,在我们用板子的时候,就在了解TI,在了解他的产品。

    总之,希望TI越来越好吧!

  • 今天遇到这个问题

    下面程序 的参考电压源为:2.92V,是通过 一个160k和33k的电阻分压得到的,模拟量A0输入电压为1.42V,计算得 1.42/2.92= 0.4863  0.4863*4095 = 1991

    但是 测得的 转化后的数字量值为:2115 ,差距也太大了,是不是下面程序哪里有问题 ?

    #include "chip.h"

    #include "adc12.h"

    #include "math.h"

    uint ad_data0;

    uint ad_data1;  

    //===================

    void init_ad(void)

    {

     ADC12CTL0 &=~ENC;

     ADC12CTL0 = SHT0_2+MSC+ADC12ON;

     ADC12CTL1 =CSTARTADD_0 + SHP +ADC12SSEL_0 + CONSEQ_1 +ADC12DIV_3;

     ADC12MCTL0 = EOS+SREF_2 +0;

     ADC12MCTL1 = EOS+SREF_2 +1;  

    }

    void close_ad(void)

    {

     ADC12CTL0 &= ~ENC;

     ADC12CTL0 &= ~ADC12ON;

    }    

    void data_convert(void)

    {

     ADC12CTL0 |=ENC +ADC12SC;

     P6SEL |= 0x01;                            // P6.0 ADC option select

     while( 1 == (ADC12IFG&ADC12BUSY))

     {

      ad_data0 = ADC12MEM0; //此处得到 ADC12MEM0为2115

      ad_data1 = ADC12MEM1;

     }

     close_ad();

    }

  • 在学习28335的时候,曾仔细思考过这款芯片的启动过程,特别是在硬件仿真模式下的运行。查阅了有关的参考文献,对这个问题仔细思考了一下,并且写了一个小结。借此机会,贴出这个小结部分,和大家分享:)如有不妥的地方,还请指正。

    ---------------------------------

    学习一款处理器芯片,搞明白芯片的运行过程,特别是程序的启动阶段,对于更好的应用芯片很有帮助。F28335来讲,它提供的方式很多。首先F28335中有片内flash,可以将程序存储在这里;其次,F28335也提供了bootloader功能;最后,F28335还具有片上OTP,用户可以在这里设定自己的启动方式。关于启动过程,在boot ROM文档里有详细的介绍,对这些启动方式都能够理解,但是对硬件仿真方式下的启动过程很是疑惑。

    在硬件仿真模式下,肯定不再需要bootloader来搬移程序,因为运行程序是通过仿真器直接放在了RAM中,那么reset CPU,程序是如何运行到设定的程序起点(c_int00)的呢?换句话说,CCS是如何将c_int00的值传递给PC的呢?在bootloader模式中,CCS会在搬移程序的时候取得这个地址。但是在仿真模式下,应当是忽略了启动模式(因为即便是设定了从flash启动,也是不会从flash中启动的)。

    不过有一种解释是这样的:就是在硬件仿真模式下屏蔽了启动模式的选择,在Resart时,强制将c_int00或者定义的程序起始地址赋给PC。这种方法比较合理,但是不知道仿真器能否完成对DSP的这种设置。暂时先这样理解。

    28335TI提供的例程中,程序的起始位置是code_start,在这里先禁止看门狗,然后再跳转到c_int00处运行;而在一般的C工程中,这个起始位置一般是c_int00;这个起始位置在编译选项(build options)中设定,这也和上面一段的理解方式是一致的。在C环境建立之前将看门狗禁止,使得程序更可靠。

    查阅到DSP2833x_CodeStartBranch.asm”中的说明,如下:

    For these examples, code_start is the first code that is executed after exiting the boot ROM code. The codestart section in the linker cmd file is used to physically place this code at the correct memory location. This section should be placed at the location the BOOT ROM will re-direct the code to. For example, for boot to FLASH this code will be located at 0x3f7ff6.

    In addition, the example DSP2833x projects are setup such that the codegen entry point is also set to the code_start label.  This is done by linker option -e in the project build options.  When the debugger loads the code,it will automatically set the PC to the "entry point" address indicated by the -e linker option. In this case the debugger is simply assigning the PC, it is not the same as a full reset of the device.

    从上面的说明,可以看到,我的理解是正确的。在仿真模式下,确实是忽略了启动模式的选择,而是让仿真器直接将程序的起始地址赋给PC的。特别对这个程序来讲,由于在C环境之前,还禁止了看门狗,程序的起始地址是code_start。但是这里有一点还应注意,在仿真模式下,模拟的是将程序引导到M0 SARAM中,所以在CMD文件中,将code_start硬件定位到了M0 SARAM的起始位置处,如果固化程序的话,需要更改code_start的位置,将其放在对应方式的位置处。

    ------------------------------------

  • 感觉身边使用MSP430的客户特别多,网上资料多,参考书籍也很多,便开始评价MSP430系列MCU。

         看到网上开发工具很多,也有免费申请的,便申请了一套学习板。开始学习使用,下载示例代码,修改测试,享受开发的乐趣。

         从硬件结构上比较,51单片机和MSP430单片机都采用冯·诺依曼结构,而PIC单片机则采用哈佛结构。这两种结构各有优点,很难说出谁好谁坏。

         MSP430单片机同样也有MSPX1XX、MSPX2XX、MSPX3XX、MSPX4XX等系列,且每一系列可选型号也很多。从低功耗方面比较,51 的可选型号几乎没有,PIC单片机是低功耗的最低功耗也达个位数uA级,但MSP430单片机则是超低功耗的,最低功耗可达到0.6uA。需要说明一点的是,在执行了休眠指令后,PIC单片机每次唤醒都需要复位一次,所以在超低功耗方面MSP430单片机表现要好点。

         当然MSP430单片机也有它的缺点,在我使用过程中,最大的不便就是位操作。

    MSP430“系”出名门,作为一种16位混合信号处理器,其独到之处在于它的超低功耗,又由于其集成了硬件乘法器,信号处理能力比起8位机大大增强,在低功耗市场应用越来越多。尤其在中国,由于有利尔达信息技术公司的全力推广,应用范围更是越来越广,大有统治低功耗市场的架式。跳舞的人多了,本人就耐不住寂寞也想热闹一把。近来做的一个项目用了MSP430,顺便记下、抄下了一些笔记,在此与大家分享一下吧,虽然都很低级,但对于入门来说,不能说没有益处。我一向认为入门最重要,入了门想深入就靠自己造化,但是入不了门或者入错门,纵然你有万千智商也无用武之地。

    1.MSP430系列并不是都有FLL、FLL+的,象X14X系列就没有。学习时要对此有个认识,如果有FLL则内部频率就比较稳定可以使用。对于14X系列DCO频率是不稳定的,误差大,所以最好是使用外部晶体

    2.MSP430的端口命名从P0---P6,但不是每个器件都有这几个端口,有的器件只有P0--P4,有的只有P1--P6(msp430f147等)。P0口没有功能选择寄存器,这点要注意。

    3.timer_A 的捕获/比较引脚和P1,注意是P1,复用,而P1有一个P1SELx的功能选择寄存器,用来选择其作为I/O还是作为timer_A使用

    4. XT1、XT2、DCO都可以作为ACLK、 MCLK、 SCLK的时钟源,具体用哪一个可以从寄存器设置。当然你可以ACLK用XT1,MCLK用XT2,SCLK用DCO产生;也可以ACLK、MCLK都用 XT2,或者都用DCO产生也未尝不可,想怎么设置时钟都行,想到那儿就可以做到那儿呵呵

    关于DCO分频控制的介绍:运用MOD参数进行调制,调制的具体含义为在32个DCO周期中插入频率为DCO+1的时钟信号,而插入的个数由MOD参数决定,其余为DCO信号,举例如下:

         DCOCTL值为7AH时,DCO频率计算公式 (748×6+825×26)/32=811,748是DCO频率,825是DCO+1频率!!!!  

    这个算法是我的理解不知对否,还请高手指点。

    5.Timer A当用作连续增计数模式时每个CCRx都可以产生中断,CCR0也没有什么特殊之处,这种方法用来产生多个定时的场合。

    6. 430的RAM是个有趣的地方,它的存储一般从0200开始,字节存储没有特别的地方,而字存储就只能从偶地址开始,这点要特别注意,当进行类型变换时必须防止重要数据被覆盖。

    7.我的总体感觉是搞清楚了430的时钟系统及其捕获比较的应用,基本就算入门了,其他方面无非就是寄存器设置还有技巧性的应用了,这方面只要做项目就会找到好的办法

  • 调试MSP430F5438时,出现问题:

    1。JTAG连接下载问题:出现JTAG没有发现MSP430F5438设备,更改改连接方法,JTAG2脚接VCC默认为JTAG供电,这个供电由USB馈电得到,注:一般情况下在JTAG供电时,4脚需悬空。在外部供电时2脚也需接到VCC上,4脚悬空或接VCC均可,一般是悬空,防止外部供电与JTAG的供电电压不匹配,引起JTAG异常。

    2.USB仿真器和并口仿真器不能同时试用。

       可能的原因:

       1)并口FET不要是什么精简版的——没有Test脚肯定不灵

       2) RST引脚上不要有外接的复位片子——通用原则

       3) IAR430的版本要在4.21及以上——4.20/4.11b可能也行,没试过;3.x的版本应该还没有5系吧...

           4) 电源问题处理好——是目标板供电还是并口供电,二选一吧,不要冲突了,这个是不是决定因素不清楚,但是肯定需要考虑。

  • 以前用过430的F149系列 感觉各种外设很多 非常好用。

    后来采用了F2618 ram很大,外设更加齐全

    而且内部带有可配置的上下拉电阻。省下了很多外部器件。后来电设一搬也采用F2618作为控制器

    再往后有接触5系列的单片机 特别是带有usb的F5529

    可以制作最小系统,甚至不需要BSL 或者仿真器可以直接烧录程序。非常方便。

    最小系统只需要几个电容,一个线性稳压器就可以完成简单的烧录程序。

    对于开发板系列,有幸得到Exp430G2 的value开发板试用,价格也很便宜,4.3美元 合人民币不到30,就能完成仿真和最小系统的功能。而且可以通过双线仿真给G2 f5系列仿真。非常超值。

    对于留名诺瑞的M3系列 只用过lm3s811 感觉6路的PWM控制很用。就是引脚比较少。

  • TMS320f2812的串口中断的问题

    开始学习DSP的时候,在串口使用时,不通过中断接收和发送信息使用了下面的例程可以实现信息的发送与接收,通过串口调试助手收到,但是使用了中断以后,程序不执行。

    我的个人分析是在程序中加了标志位,使得部分串口中断程序没有执行,所以只能使用分时收发。

    下面为不是中断执行的程序:

     

       Send_Flag = 0;

       #if SCIA_INT

    /*设置中断服务程序入口地址*/

    EALLOW; // This is needed to write to EALLOW protected registers

    PieVectTable.TXAINT = &SCITXINTA_ISR;

    PieVectTable.RXAINT = &SCIRXINTA_ISR;

    EDIS;   // This is needed to disable write to EALLOW protected registers

    /*开中断*/

    IER |= M_INT9;

    #endif

    EINT;   // Enable Global interrupt INTM

    ERTM; // Enable Global realtime interrupt DBGM

    for(;;)

    {

     if((SciaTx_Ready() == 1) && (Send_Flag == 1))

     {

      SciaRegs.SCITXBUF = Sci_VarRx;

      Send_Flag = 0;

      i++;

      if(i == j)

      {

       i = 0;

       j = 0;

      }

     }

     #if !SCIA_INT

     if(SciaRx_Ready() == 1)

     {

      Sci_VarRx[j] = SciaRegs.SCIRXBUF.all;

      Send_Flag = 1;

      j++;

      if(j == 100)

      {

       j = 0;

      }

     }

     #endif

    }

    使用串口中断程序如下:

    我将标志位删除后,执行改程序,

    #include "DSP28_Device.h"

    unsigned int Sci_VarRx[100];

    unsigned int i,j;

    unsigned int Send_Flag;

    unsigned int * Led8  = (unsigned int *) 0x4100;

    //#define SCIA_INT 1

    interrupt void SCITXINTA_ISR1(void);

    interrupt void SCIRXINTA_ISR1(void);

    void main(void)

    {

    /*初始化系统*/

    InitSysCtrl();

    /*关中断*/

    DINT;

    IER = 0x0000;

    IFR = 0x0000;

    /*初始化PIE中断*/

    InitPieCtrl();

    /*初始化PIE中断矢量表*/

    InitPieVectTable();

    /*初始化SCIA寄存器*/

       InitSci();

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

       {

        Sci_VarRx = 0;

       }

       i = 0;

       j = 0;

       Send_Flag = 0;

      #if SCIA_INT

    /*设置中断服务程序入口地址*/

    EALLOW; // This is needed to write to EALLOW protected registers

    PieVectTable.TXAINT = &SCITXINTA_ISR1;

    PieVectTable.RXAINT = &SCIRXINTA_ISR1;

    EDIS;   // This is needed to disable write to EALLOW protected registers

    /*开中断*/

    IER |= M_INT9;

    #endif

    EINT;   // Enable Global interrupt INTM

    ERTM; // Enable Global realtime interrupt DBGM

    for(;;)

    {

     if(1 && (Send_Flag == 1))

     {

      SciaRegs.SCITXBUF = Sci_VarRx[0];

      while(SciaRegs.SCICTL2.bit.TXRDY!=1);

      Send_Flag = 0;

      i++;

      if(i == j)

      {

       i = 0;

       j = 0;

      }

     }

     #if !SCIA_INT

     if(SciaRx_Ready() == 1)

     {

      Sci_VarRx[j] = SciaRegs.SCIRXBUF.all;

      Send_Flag = 1;

      j++;

      if(j == 100)

      {

       j = 0;

      }

     }

     #endif

    }

    }  

    interrupt void  SCITXINTA_ISR1(void)

    {

    }

    interrupt void SCIRXINTA_ISR1(void)

    {

    DINT;

    PieCtrl.PIEACK.bit.ACK9=1;

    Sci_VarRx[0] = SciaRegs.SCIRXBUF.all;

    Send_Flag = 1;

    j++;

    // if(j == 100)

    // {

    //  j = 0;

    // }

      *Led8=j;

    SciaRegs.SCICTL1.bit.SWRESET =1;

    PieCtrl.PIEIFR9.bit.INTx1=1;

    EINT;

    }

    程序虽然编译正确,但是程序没有执行,请问这是什么原因?

  • 回顾过去,使用TI的MCU都有6个年头了,目前公司主要产品使用了MSP430的F149 F168 F5438 F2122几种比较多,新的产品项目除了低功耗要求高的,基本上都开始选用Stellaris的LM3S8962 LM3S6911系列芯片了,说起Stellaris我和TI还是很有缘的,记得好像是2010年上半年的一次TI产品推介会吧,我去参加了,刚好TI在力推Stellaris的M3系列产品,听了之后比较感兴趣,哪知道推介会结束之后的抽奖环节,我抽到了头奖,奖励一块8962的开发板,回到公司好好研究了一个星期,正好公司一个新项目需要用到以太网功能,刚好派上用场了,目前公司我负责的有3个项目6个产品选用了8962和6911,使用良好,唯一有点担心的就是发热问题,不过目前看问题不大,目前小批量生产了1000台左右,年底应该可以量产了,总的来说TI的产品和服务都很不错!希望TI以后能提供更好的产品和服务!

  • 以前一直在做8/16位开发,主要是PIC和8051,2010年的时候TI弄MCU DA我报了名,但没有去成。不过惊喜的是竞然收到了邮件说参加了MCU DAY的可以49元买8962+CAN的开发板(呵呵,没去也有这待遇:) ~~~),毫不犹豫的用现大洋买下,从此开始了Stellaris的开发,并最终应用到了一个2轴数控系统的项目上(用了LM3S5791)。

    以前从没玩过ARM,没玩过USB、CAN、Ethernet,TI的外设功能也相对比PIC和8051强大很多,从之前的基础上从零开始确实很难。特别是USB、Ethernet以前更没接触。但TI在例程、驱动以及应用笔记方面确实做得非常好。在这个其础之上开发相当的简单,很多细节都不需理会。我的LM3S5749 USB操作就是完全借用3748的MSC例程做出来的(仅仅是升级了fatfs到最新版,并实现相对目录操作)。

    Stellaris感觉官方推得很买力,但80Mhz的器件还是不好买,本来是用5791,案子都按这个做了结果代理商说没得卖,只是少数几个9系列的有得卖,晕得不行。想想这么难买,Flash还有擦写100次的bug就不情愿的切到了5749,虽然性能下降了但还好是没有影响到案子的顺利完工。

    喜欢Stellaris,期待TI在性能、外设、价格上有新的突破。

  •    我是一名大四本科生,在大三的暑假留校参与完成了一个由基于MSP430F1611的机械手操控的中国象棋盘的教师科技制作项目,在这期间,借由这个项目,我逐渐了解、认识、掌握了MSP430单片机的基本使用方法。

       由于我校是全国高校中最早引进MSP430单片机用于教学与实践的,我们积累了大量的MSP430单片机学习应用资料,所以我的单片机入门是直接从MSP430单片机开始的。参考书是我校一位老师编写的《MSP430系列超低功耗单片机系统设计与实践》,其中以MSP430FE425为例,分别阐述了MSP430FE425的片上配置资源、各种资源的使用方法,以及在IAR for MSP430的开发环境下对各种资源使用的各种例子程序。正是从MSP430FE425开始,我进入了430单片机的世界。

       先说说MSP430FE425,它各种资源齐全,特别是带有液晶驱动,这一点对于学生来说很好,可以使得学生在有限的片子上尽可能多的见识各种资源,熟悉给各种资源编程,得到多方面的锻炼。在基于MSP430FE425的学习板上,我学习了流水灯,测温计,定时器应用,电机PWM调速,触摸按键设计,简单音乐设计,液晶显示设计等等程序,对该型单片机所配置的资源有了更加深入的了解。在平时使用中,该型单片机有时会让人有I/O口(共14个)不够用的感觉,我想是因为该型单片机把许多引脚分配给了液晶驱动的缘故。

       再说说MSP430F1161,这是一款比MSP430FE425的配置资源更加强大的单片机,包含有48KBflash;1024BRam;8通道12bitA/D;双12bitD/A;DMA;48个I/O口;16位WDT;1个16位Timer_A(3个捕获/比较寄存器);1个16位Timer_B(7个捕获/比较寄存器);2个USART接口;I2C;MPY;比较器_A;温度传感器。我所做的项目主要用到flash,ram,Timer,UART模块,在PC机上的上位机程序发送数据,并通过UART模块传送给下位机,来控制立体坐标系中的x,y,z三个坐标方向来分别驱动三个直线电机,使得机械手走到准确的位置,再驱动一个舵机控制机械手的开合,来完成机械手对象棋棋子的夹持,然后再驱动电机使机械手走到目标位置,放下棋子,完成一次走棋;同时每个方向上要加装两个限位开关以防止电机跑飞,所以整体来说,就要求单片机的I/O口比较多,而MSP430F1161正好满足项目的要求,我们便采用其作为系统下位机的MCU。在编写程序中遇到的最大的的问题就是中断的执行,程序中电机的驱动,限位开关的触发等等都是写成中断函数的形式,所以有许多中断的嵌套,曾经发生过在x,y方向上走位完成后,z方向上程序卡住不执行了,后来经过检查发现是因为程序进入电机的中断后,又执行了限位开关的中断,进入了死循环,导致后续的程序无法执行,处理办法是进入电机中断后,就把总中断关闭,以防止其他中断的干扰,这样终于解决了这个问题,项目也顺利的完成。

       以上就是我学习使用MSP430系列单片机的一些认识和体会,今后我还将继续钻研,努力把MSP430单片机用精用通。

  •        本人在大三上学期参加过一个实验室开发项目,主题是基于zigbee的无线传感网络。首先我先贴出我那时候完成的报告的摘要:

          本次实验研究,目的在于基于一种低速率,低功耗,短距离的无线网络协议,搭建一个实用可靠的无线传感网络,并验证无线传感网络在智能家居应用的可行性。本方案中选用由射频芯片与工业级C8051结合的CC2530作为无线微控芯片,附上温湿度传感器,基于Zigbee 2007搭建一个星型结构的无线传感网络。后期应用开发中,在传感节点中加入LED驱动电路,附上光照传感器与声音传感器,升级为多功能无线灯控网络。最后,我们基于VB开发了一套数据管理与控制软件,能够把从节点接收到的数据,通过串口传输至PC终端,最终显示到上位机中;并通过上位机发送控制命令,切换节点LED的显示功能模式,最终实现传感网络的全双工通信功能

          刚初次接触zigbee的时候,其实我第一款接触TI的产品不是CC2530,而是它的前身CC2430。其实CC2430就是一个工业级的8位51单片机+一个射频模块。刚开始那个月,基本多事熟悉单片机的操作,跑一下流水灯,中断,数码管之类的外设。后来熟悉了IO口与寄存器的操作之后,又外加了一些温度传感器,红外遥控之类的模块,并尝试编程控制。等单片机基本入门后,我就开始接触TI的ZStack;看这一些有关协议栈的文档与学习视频,进行了一个月左右的时间的学习;并在官方提供的例程Controller_Switch中学会了协调器建立网络,节点加入网络,绑定的流程。

          待我基本熟悉协议栈ZDO与应用层的大概框架,我开始升级我的硬件装备,CC2530。CC2530的特性我也不多介绍,zigbee2007的协议栈功能更加完善,也修复了很多BUG。再后来,我学会了操作串口的中断,ADC的使用,还有定时器产生PWM信号等等。最终出色顺利完成项目。

          下面我贴出一个串口的接收中断函数,因为在协议栈使用串口一般是用DMA模式,使用中断的方法较少,而且编写中断函数有一定规范,所以提供大家参考一下,实测是可以用的。

    /**************************************************************************///UART接收中断函数
    _PRAGMA(vector=URX0_VECTOR)__near_func __interrupt void URX0_IRQ(void)

    {
        count++;
        TBuf[count-1]=U0DBUF;
        TBuf1[count-1]=U0DBUF;
        if((TBuf[0]==0x01)||(TBuf[0]==0x02))
        {
          if(count==4)
          {
             if( TBuf[0]==0x01)
             {zb_SendDataRequest( Endpoint1shortadd, TOGGLE_LIGHT_CMD_ID, 4,
                                 (uint8 *)TBuf, myAppSeqNumber, 0, 0 );}
             if( TBuf[0]==0x02)
             {zb_SendDataRequest( Endpoint2shortadd, TOGGLE_LIGHT_CMD_ID, 4,
                                 (uint8 *)TBuf, myAppSeqNumber, 0, 0 );}
             count=0;
             HalLedSet(HAL_LED_3, HAL_LED_MODE_TOGGLE);//cyjtest
          }
        }
       
        else if((TBuf1[0]==0xff)||(TBuf1[0]==0xfe))
        {
           if(count==2)
           {
             if( TBuf1[1]==0x01)
             {zb_SendDataRequest( Endpoint1shortadd, SOUND_LIGHT_CMD_ID, 2,
                                 (uint8 *)TBuf1, myAppSeqNumber, 0, 0 );}
             if( TBuf1[1]==0x02)
             {zb_SendDataRequest( Endpoint2shortadd, SOUND_LIGHT_CMD_ID, 2,
                                 (uint8 *)TBuf1, myAppSeqNumber, 0, 0 );}
             count=0;
             HalLedSet(HAL_LED_3, HAL_LED_MODE_TOGGLE);//cyjtest
           }
        }
       
        else{count=0;}
    }
    /**************************************************************************//


  • 我是一名在校的研究生,以前使用的都是51系列的单片机。后来经过导师的指导,开始学习Cotex-M3内核的芯片,学习的第一块芯片就是在TI申请的LM3S1138。然后使用自己制作的简易实验板开始学习。不得不说,第一次接触到使用库函数的编程方法,感觉比使用51系列的单片机编程方便很多。我在学习中感到与使用51最大不同就是它的串行通讯模块和中断系统。

    串行模块在使用时不是每次只能收发一个字节的数据不过在就收数据的时候要打开超时中断并进行相应的处理否则在数据无法达到预设的深度时会造成数据无法接收的后果。

    群星Cotex-M3中断系统中断资源十分丰富,每一个GPIO引脚都可以作为中断源不过在使用时要软件清除中断标志。

  •           我对TI的MCU是从430开始的,那时在学校参加“TI杯”的电子设计大赛。官方指定使用TI的MCU,我们最终选择了MSP430。当我们使用的时候,就被它强大的功能和超低的功耗所折服了。但是当时没怎么看430的知识。比赛结束后我也就再没有使用过MSP430,直到现在我准备好好学习一个MCU的时候。我的脑子里第一个反应就是MSP430,最近我看了它的时钟设置,我使用的是MSP430F4270。下面我就写写我的驱动的NOKIA 5110的屏,调试环境是8MHz的晶振,IAR4.30。

    下面是引脚的配置:

    LCD_RST    4 ---------P2.4
    LCD_CE      3 ---------P2.3
    LCD_DC      2 ---------P2.2
    LCD_DIN     1 ----------P2.1
    LCD_CLK    0----------P2.0

    NOKIA5110的初始化:

               /*-----------------------------------------------------------------------
                LCD_init          : 5110LCD初始化程序
                -----------------------------------------------------------------------*/

    void delay_1us(void)                 //1us延时函数
    {
       unsigned int i;
      for(i=0;i<100;i++);
      
    }

      void delay_1ms(void)                 //1ms延时函数
      {
       unsigned int i;
       for (i=0;i<1140;i++);
      }
     
    void delay_nms(unsigned int n)       //N ms延时函数
      {
       unsigned int i=0;
       for (i=0;i<n;i++)
       delay_1ms();
      }

    void LCD_init(void)
      {
      // 产生一个让LCD复位的低电平脉冲
      // LCD_RST = 0;
     
        LCD_5110_DIR |= (0x01 << LCD_RST) + (0x01 << LCD_CE) + (0x01 << LCD_DC)
           + (0x01 << LCD_DIN) + (0x01<< LCD_CLK);
     
       LCD_5110_OUT &= ~(0x01 << LCD_RST);
        delay_1us();

      // LCD_RST = 1;
       LCD_5110_OUT |= (0x01 << LCD_RST);
       
      // 关闭LCD
       //LCD_CE = 0;
        LCD_5110_OUT &= ~(0x01 << LCD_CE);
        delay_1us();
      // 使能LCD
       //LCD_CE = 1;
       LCD_5110_OUT |= (0x01 << LCD_CE);
        delay_1us();

        LCD_write_byte(0x21, 0); // 使用扩展命令设置LCD模式
        LCD_write_byte(0xc8, 0); // 设置偏置电压
        LCD_write_byte(0x06, 0); // 温度校正
        LCD_write_byte(0x13, 0); // 1:48
        LCD_write_byte(0x20, 0); // 使用基本命令
        LCD_clear();             // 清屏
        LCD_write_byte(0x0c, 0); // 设定显示模式,正常显示
           
        // 关闭LCD
        LCD_5110_OUT &= ~(0x01 << LCD_CE);
      }

    详细的程序见附件。

    DEBUG后没有错误后,将调试器连接到目标板。注意目标板的复位脚应为高电平,否则程序将不能下载进去。由于我使用的是8MHz的晶振,所以在使用MCU的时钟初始化时要加下列语句:

     FLL_CTL0 |= XTS_FLL;//(高频晶振模式)
     FLL_CTL0 |= XCAP0PF;//外部使用了电容,内部无需匹配电容。

    编译后就可以下载程序了。然后RUN一下,屏幕就可以显示了!

    NOKIA5110.rar
  • 午休中, 就来凑个热闹把。

         现在正在用MSP430F5438A开发一款RTU。遇到过一个很奇怪的问题,初期调试程序模块的时候,程序的加载和运行都正常,但只要把所有模块组合到一起就无法运行,连仿真都无法做到(加载完成后始终运行在_DATA16_MEMZERO函数里面,不进入main函数)。

         开始以为是程序问题,查了很久没有头绪。后来发现仿真时死循环的程序_DATA16_MEMZERO并不是真的在死循环,其跳转参数在单步执行的情况下可以正常计数。但一旦全速运行,该参数会被不明原因清零。由于该函数不是用户程序,用户程序影响到该函数参数的地方只有程序规模和定义变量的多少了。

        果然,减少程序模块后可以正常加载及运行了。最后判断结果是:处理量太大,时间过长,导致内部看门狗复位!

        在修改了系统的cstartup.s43文件中的看门狗机制后,问题消失了。

         我在这里有个疑惑,我的程序没有超过芯片自带的flash、ram容量,系统自带的初始化函数怎么会在处理内存数据的时候超时导致看门狗复位呢?

  • 由于公司产品的侧重点,从参加工作到现在所使用的DSP主要都是C2000系列的,从最开始的C206,2407,2812一直到28335,可以说TI的DSP运用一直是我工作的重点之一。相对其它的产品,TI的DSP从产品的分类和网上的技术支持都是非常丰富的。

    如果说这些年来的使用过程中有什么大的问题,就是在使用28335的过程中,无意中发现,当芯片在零下35度到40度时,用手在芯片上方20-30mm,(不接触芯片)晃过,疑似芯片会受到静电的感应复位。其后的产品运用中被迫上方加装金属的屏蔽罩解决。常温中不出现该问题。

  • 看了楼上诸位发表的各自的经验,我也来分享一下工作中使用MSP5438A遇到的小问题,是关于AD模块的问题。这款芯片在使用过程中我们发现AD模块偶尔不能产生中断,刚开始以为是芯片的个体问题,后来发现第一批样品中有5片都是这样的问题,我们才意识到可能是这个芯片的bug。后来咨询代理公司的技术支持,我们将程序改为初始化时将AD模块多初始化几次。经过测试,后来就再也没有出现过该问题。不知道别的同行有没有遇到这样的问题,如果遇到了可以参考我们的解决方法试试。

  • o(∩_∩)o

    我们课堂上教学用的也是51,还有微机原理用的8086、8088。这两门课的学习,让我们了解到了微处理器的原理,知道了啥叫总线、中断机制、定时器、通信、外扩存储器等等。学完之后,再去了解ARM、DSP那些,就发觉他们都是一个样的。

    与TI的结缘,是从TI M3 Day 2010开始的。报名的时候,是以本科生身份参加的,当TI给我发来确认函的时候,心中是一份惊喜。研讨会让我距离接触了TI,下午的动手课程让我体验了一下StellarisWare给编程带来便利,也是从那时开始关注着TI,订阅了TI很多的电子报、资讯等。

    TI的Cortex-M3,使用StellarisWare库文件来开发,给人的第一感受就是ARM入门的门槛大大降低了,TI的M3库比较少使用结构体作为函数入口参数,使用起来比较浅显易懂。只要有单片机基础,不足一天,就可以踏入ARM的世界。

    TI M3,外设丰富,常见的GPIO中断、uart(带FIFO)、I2C、SPI……还有强大点的USB、以太网,可以说TI M3互联性是倍棒的。

    TI提供非常丰富的资料,TI的代理商利尔达、周立功等都有很多相关的模块使用说明,库函数使用方法介绍等文档,给我们的设计、使用带来了极大的便利。

  •   当我大学毕业的时候,我只是对 51 单片机有一点基础,认真自学了几个月。可是谁也不会想到几个月我遇到了 Stellaris,我找到第一份工作,是做 Stellaris MCU 推广。看到 ”LM3S“ 几个字母,我感到很迷茫,我不知道这到底是个什么东西,没有任何人和我讲过关于它的任何信息。我的 BOSS 给我发了份《Cortex-M3 权威指南》和《LM3S8962 Datasheet》让我自己看。我开始认真研究这两个资料,遇到不明白的地方就不断地去 Google,不轻易放过一个未知点,我的生活就是以 Stellaris 为中心。越学习越兴奋,只想说,对 Stellaris 相见恨晚,如果是在 2006 就接触到的话该有多好。

      学习 Stellaris MCU,让我不仅仅学到了这类优秀的 MCU 本身的各种外设,还学到很多与它相关的知识,比如 Ethernet,CAN,USB.....我超喜欢 Stellaris MCU 的英文资料,让我真正感觉到设计 Stellaris 的工程师是多么地了不起,他们是真正的倾注心血在设计一类优秀的 MCU,尽管 Stellaris 在客观上有些地方不足,但是它绝对是一类可以投注精力去学习,去应用的 MCU.

        学习 Stellaris M3 ,除了要掌握其丰富的各种外设操作之外,还要学习一些关于 Ethernet,CAN,USB 的基本知识,还好有 StellarisWare ,这个软件包真的很强大,里边的好多编程的范例值得深入地去分析和借鉴,实在是学习 MCU Firmware 开发的好材料。Driverlib 让工程师不再把大量的时间放在对寄存器底层的配置上,而是可以用更多精力去思考如何快速的设计出优秀的产品。

       Stellaris 目前主要是 TI M3,TI M4 也即将到来,这让感到无比兴奋,Stellaris 必将是 MCU 中的群星,一群闪亮的明星!

     从过去到将来,Stellaris 不仅仅是我的工作的一部分,也将是我生活的一部分,它已经融入,且不会离开。

     对 Stellaris 的热爱会一直持续下去,并将激励我用自己的努力让更多的工程师一起来分享 Stellaris 的精彩。

  • 到了深夜,我还是忍不住分享我学习TI的msp430f1611和tms320f2812的心得。

    我接触430已经有三年了,起初我感觉430很难学,特别是他的I/O口设置起来很麻烦,相对与51单片机而言。对I/O的操作既要设定为I/O口模式,又要设定为输出输入模式,起初编程时,我总是犯错,总是在I/O的初始化问题犯错,后来通过不断的学习,我发现其实430的I/O使用起来很方便,因为复用功能特别强大。

    下面谈一下我使用该芯片的实例吧。

       最开始我使用430做了辆循迹小车,参加了学校举行的智能小车比赛,通过两个也与430的接触,我发现在控制小车方面430的功能太强大了,在通过自己的不断摸索下,顺利的解决了I/O的初始化问题,并且顺利拿到了比赛第一名的好成绩。从此我爱上了430.

      后来我利用430到一些实际科研项目中,当我利用430作为数字电源控制芯片时,我曾经有放弃使用430的冲动,在使用的过程中,我发现只要外界电压电流变化过大,430就要复位,或者直接死机,最令人受不了的是直接控制功率电源很容易烧掉I/O端口,曾经我一连烧掉3个端口,后来经验丰富了,我把430的供电电源隔离,端口与继电器或者是DAC用光耦隔离,我发现问题一下子就解决了。

     现在三年了,我使用430做了很多项目,其中遇到了很多问题,我都一一解决了,现在使用430很顺手,感觉现在有点离不开他了!

  • 这只是我在学习TI公司生产的16位超的功耗单片机MSP430的随笔,希望能对其他朋友有所借鉴,不足之处还请多指教。

    讲解430的书现在也有很多了,不过大多数都是详细说明底层硬件结构的,看了不免有些空洞和枯燥,我认为了解一个MCU的操作首先要对其基础特性有所了解,然后再仔细研究各模块的功能。

    1.首先你要知道msp430的存储器结构。典型微处理器的结构有两种:冯。诺依曼结构——程序存储器和数据存储器统一编码;哈佛结构——程序存储器和数据存储器;msp430系列单片机属于前者,而常用的mcs51系列属于后者。

    0-0xf特殊功能寄存器;0x10-0x1ff外围模块寄存器;0x200-?根据不同型号地址从低向高扩展;0x1000-0x107f seg_b0x1080_0x10ff seg_a 供flash信息存储剩下的从0xffff开始向下扩展,根据不同容量,例如149为60KB,0xffff-0x1100

    2.复位信号是MCU工作的起点,430的复位信号有两种:上电复位信号POR和上电清除信号PUC。POR信号只在上电和RST/NMI复位管脚被设置为复位功能,且低电平时系统复位。而PUC信号是POR信号产生,以及其他如看门狗定时溢出、安全键值出现错误是产生。但是,无论那种信号触发的复位,都会使msp430在地址0xffff处读取复位中断向量,然后程序从中断向量所指的地址开始执行。复位后的状态不写了,详见参考书,嘿嘿。

    3.系统时钟是一个程序运行的指挥官,时序和中断也是整个程序的核心和中轴线。430最多有三个振荡器,DCO内部振荡器;LFXT1外接低频振荡器,常见的32768HZ,不用外接负载电容;也可接高频450KHZ-8M,需接负载电容;XT2接高频450KHZ-8M,加外接电容。(经验中发现,接XT2时,需要注意自己开启XT2,并延时50us等待XT2起振,然后手工清除IFG1中的OFIFG位,其操作顺序为:打开XT2->等待XT2稳定->切换系统时钟为XT2)

    430有三种时钟信号:MCLK系统主时钟,可分频1 2 4 8,供cpu使用,其他外围模块在有选择情况下也可使用;SMCLK系统子时钟,供外围模块使用,可选则不同振荡器产生的时钟信号;ACLK辅助时钟,只能由LFXT1产生,供外围模块。

    4.中断是430处理器的一大特色,因为几乎每个外围模块都能产生,430可以在没有任务时进入低功耗状态,有事件时中断唤醒cpu,处理完毕再次进入低功耗状态。

    整个中断的响应过程是这样的,当有中断请求时,如果cpu处于活动状态,先完成当前命令;如果处于低功耗,先退出,将下一条指令的pc值压入堆栈;如果有多个中断请求,先响应优先级高的;执行完后,等待中断请求标志位复位,要注意,单中断源的中断请求标志位自动复位,而多中断的标志位需要软件复位;然后系统总中断允许位SR.GIE复位,相应的中断向量值装入pc,程序从这个地址继续执行。

    这里要注意,中断允许位SR.GIE和中断嵌套问题。如果当你执行中断程序过程中,希望可以响应更高级别的中断请求时,必须在进入第一个中断时把SR.GIE置位。

    其实,其他的外围模块时钟沿着时钟和中断这个核心来执行的。具体的结构我也不罗索了,可以参考430系列手册。

    C语言编程起步

    因为常用的430编程开发是c语言,所以下面讲解C语言对430编程的整体结构。基本上属于框架结构,即整体的模块化编程,其实这也是硬件编程的基本法则拉(可不是我规定的法则哦)。

    首先是程序的头文件,包括#include <MSP430x14x.h>,这是14系列,因为常用149;其他型号可自己修改。还可以包括#include "data.h" 等数据库头文件,或函数变量声明头文件,都是你自己定义的哦。

    接着就是函数和变量的声明 void Init_Sys(void),即系统初始化。系统初始化是个整体的概念,广义上讲包括所有外围模块的初始化,你可以把外围模块初始化的子函数写到 Init_Sys()中,也可以分别写各个模块的初始化。但结构的简洁,最好写完系统的时钟初始化后,其他所用到的模块(包括一些中断初始化)也在这里初始化。

    void Init_Sys()

    {

      unsigned int i;

      BCSCTL1&=~XT2OFF;                //打开XT2振荡器

      do

      {

      IFG1 &= ~OFIFG;              // 清除振荡器失效标志

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

    // 延时,等待XT2起振

    }

    while ((IFG1 & OFIFG) != 0);    // 判断XT2是否起振

    BCSCTL2 =SELM_2+SELS;           //选择MCLK、SMCLK为XT2

    //以下对各种模块、中断、外围设备等进行初始化

    ........................................

    _EINT(); //打开全局中断控制

    }

    这里涉及到时钟问题,通常我们选择XT2为8M晶振,也即系统主时钟MCLK为8M,cpu执行命令以此时钟为准;但其他外围模块可以在相应的控制寄存器中选择其他的时钟,ACLK;当你对速度要求很低,定时时间间隔大时,就可以选择ACLK,例如在定时器Timea初始化中设置。

    主程序:

    void main( void )

    {

      WDTCTL = WDTPW + WDTHOLD;//关闭看门狗

     InitSys();  

     //初始化

    //自己任务中的其他功能函数

    。。。。。。。。。。。。。。。。。。。。。

      while(1);

    }

    主程序之后我要讲讲中断函数,中断是你做单片机任务中不可缺少的部分,也可以说是灵魂了(夸张吗)。

    /***********************************************************************

    各中断函数,可按优先级依次书写

    ***********************************************************************/

    举个定时中断的例子:

    //初始化

    void Init_Timer_A(void)

    {

    TACTL = TASSEL0 + TACLR;               // ACLK, clear TAR

           CCTL0 = CCIE;                         // CCR0 中断使能

           CCR0=32768;                           //定时1s

           TACTL|=MC0;                           //增计数模式

       }

    //     中断服务

    #pragma vector="TIMERA0"_VECTOR

    __interrupt void TimerA0()

    {

    // 你自己要求中断执行的任务

    }

    当然,还有其他的定时,和多种中断,各系列芯片的中断向量个数也不同。

  • 半个月了,天天到这里来看看,确实是受益匪浅呀!希望经常举办这样的活动,加强大家的沟通。

  • 最开始接触M3是接触的ST的芯片,当时觉得M3挺强大的,还记得当时测了下进入中断的时间是不是比ARM7快。然后一直用ST的芯片。

    直到后来我一个同学拿着一个板子,上面是LM3S8962,才开始注意到TI的M3。当时看了一个ti提供的例程,用库函数写的,整个程序下来,

    清清楚楚,特别容易理解和上手,而且听同学说ti还比较大方,所以自己马上也申请个板子,踏上了自己LM3S的开始之旅。下面是两个调试过程中需要注意的问题。

    1. 如果用寄存器操作来使用外设,最好在每个外设配置完之后加个延时,延时几个指令周期就可以。因为如果不延时,可能会出现外设不能驱动的情况。

    2. LM3S的红外线功能的时候,要先配置uart为红外线模式,然后再配置波特率,串口电器特性等,否则在发送开始会有可能多触发一次发送中断。

    3. 参考库函数手册最好参考最新的英文版手册,如果参考中文的老版,会丢掉很多有用的库函数。

  • 本人学习Ti公司也不算久,就两年左右,这两年学的不多,总结一些自己和他人的经验也是有点的,现在和别人分享一下:

    在研制带处理器的电子产品时,如何提高抗干扰能力和电磁兼容性?

    一、下面的一些系统要特别注意抗电磁干扰:

    1、微控制器时钟频率特别高,总线周期特别快的系统。

    2、系统含有大功率,大电流驱动电路,如产生火花的继电器,大电流开关等。

    3、含微弱模拟信号电路以及高精度A/D变换电路的系统。

    二、为增加系统的抗电磁干扰能力采取如下措施:

    1、选用频率低的微控制器:

    选用外时钟频率低的微控制器可以有效降低噪声和提高系统的抗干扰能力。同样频率的方波和正弦波,方波中的高频成份比正弦波多得多。虽然方波的高频成份的波的幅度,比基波小,但频率越高越容易发射出成为噪声源,微控制器产生的最有影响的高频噪声大约是时钟频率的3倍。

    2、减小信号传输中的畸变

    微控制器主要采用高速CMOS技术制造。信号输入端静态输入电流在1mA左右,输入电容10PF左右,输入阻抗相当高,高速CMOS电路的输出端都有相当的带载能力,即相当大的输出值,将一个门的输出端通过一段很长线引到输入阻抗相当高的输入端,反射问题就很严重,它会引起信号畸变,增加系统噪声。当Tpd>Tr时,就成了一个传输线问题,必须考虑信号反射,阻抗匹配等问题。

    信号在印制板上的延迟时间与引线的特性阻抗有关,即与印制线路板材料的介电常数有关。可以粗略地认为,信号在印制板引线的传输速度,约为光速的1/3到1/2之间。微控制器构成的系统中常用逻辑电话元件的Tr(标准延迟时间)为3到×××s之间。

    在印制线路板上,信号通过一个7W的电阻和一段25cm长的引线,线上延迟时间大致在4~20ns之间。也就是说,信号在印刷线路上的引线越短越好,最长不宜超过25cm。而且过孔数目也应尽量少,最好不多于2个。

    当信号的上升时间快于信号延迟时间,就要按照快电子学处理。此时要考虑传输线的阻抗匹配,对于一块印刷线路板上的集成块之间的信号传输,要避免出现Td>Trd的情况,印刷线路板越大系统的速度就越不能太快。

    用以下结论归纳印刷线路板设计的一个规则:

    信号在印刷板上传输,其延迟时间不应大于所用器件的标称延迟时间。

    3、减小信号线间的交叉干扰:

    A点一个上升时间为Tr的阶跃信号通过引线AB传向B端。信号在AB线上的延迟时间是Td。在D点,由于A点信号的向前传输,到达B点后的信号反射和AB线的延迟,Td时间以后会感应出一个宽度为Tr的页脉冲信号。在C点,由于AB上信号的传输与反射,会感应出一个宽度为信号在AB线上的延迟时间的两倍,即2Td的正脉冲信号。这就是信号间的交叉干扰。干扰信号的强度与C点信号的di/at有关,与线间距离有关。当两信号线不是很长时,AB上看到的实际是两个脉冲的迭加。

    CMOS工艺制造的微控制由输入阻抗高,噪声高,噪声容限也很高,数字电路是迭加100~200mv噪声并不影响其工作。若图中AB线是一模拟信号,这种干扰就变为不能容忍。如印刷线路板为四层板,其中有一层是大面积的地,或双面板,信号线的反面是大面积的地时,这种信号间的交叉干扰就会变小。原因是,大面积的地减小了信号线的特性阻抗,信号在D端的反射大为减小。特性阻抗与信号线到地间的介质的介电常数的平方成反比,与介质厚度的自然对数成正比。若AB线为一模拟信号,要避免数字电路信号线CD对AB的干扰,AB线下方要有大面积的地,AB线到CD线的距离要大于AB线与地距离的2~3倍。可用局部屏蔽地,在有引结的一面引线左右两侧布以地线。

    4、减小来自电源的噪声

    电源在向系统提供能源的同时,也将其噪声加到所供电的电源上。电路中微控制器的复位线,中断线,以及其它一些控制线最容易受外界噪声的干扰。电网上的强干扰通过电源进入电路,即使电池供电的系统,电池本身也有高频噪声。模拟电路中的模拟信号更经受不住来自电源的干扰。

    5、注意印刷线板与元器件的高频特性

    在高频情况下,印刷线路板上的引线,过孔,电阻、电容、接插件的分布电感与电容等不可忽略。电容的分布电感不可忽略,电感的分布电容不可忽略。电阻产生对高频信号的反射,引线的分布电容会起作用,当长度大于噪声频率相应波长的1/20时,就产生天线效应,噪声通过引线向外发射。

    印刷线路板的过孔大约引起0.6pf的电容。

    一个集成电路本身的封装材料引入2~6pf电容。

    一个线路板上的接插件,有520nH的分布电感。一个双列直扦的24引脚集成电路扦座,引入4~×××H的分布电感。

    这些小的分布参数对于这行较低频率下的微控制器系统中是可以忽略不计的;而对于高速系统必须予以特别注意。

    6、元件布置要合理分区

    元件在印刷线路板上排列的位置要充分考虑抗电磁干扰问题,原则之一是各部件之间的引线要尽量短。在布局上,要把模拟信号部分,高速数字电路部分,噪声源部分(如继电器,大电流开关等)这三部分合理地分开,使相互间的信号耦合为最小。

    7、处理好接地线

    印刷电路板上,电源线和地线最重要。克服电磁干扰,最主要的手段就是接地。

    对于双面板,地线布置特别讲究,通过采用单点接地法,电源和地是从电源的两端接到印刷线路板上来的,电源一个接点,地一个接点。印刷线路板上,要有多个返回地线,这些都会聚到回电源的那个接点上,就是所谓单点接地。所谓模拟地、数字地、大功率器件地开分,是指布线分开,而最后都汇集到这个接地点上来。与印刷线路板以外的信号相连时,通常采用屏蔽电缆。对于高频和数字信号,屏蔽电缆两端都接地。低频模拟信号用的屏蔽电缆,一端接地为好。

    对噪声和干扰非常敏感的电路或高频噪声特别严重的电路应该用金属罩屏蔽起来。

    8、用好去耦电容。

    好的高频去耦电容可以去除高到1GHZ的高频成份。陶瓷片电容或多层陶瓷电容的高频特性较好。设计印刷线路板时,每个集成电路的电源,地之间都要加一个去耦电容。去耦电容有两个作用:一方面是本集成电路的蓄能电容,提供和吸收该集成电路开门关门瞬间的充放电能;另一方面旁路掉该器件的高频噪声。数字电路中典型的去耦电容为0.1uf的去耦电容有5nH分布电感,它的并行共振频率大约在7MHz左右,也就是说对于10MHz以下的噪声有较好的去耦作用,对40MHz以上的噪声几乎不起作用。

    1uf,10uf电容,并行共振频率在20MHz以上,去除高频率噪声的效果要好一些。在电源进入印刷板的地方和一个1uf或10uf的去高频电容往往是有利的,即使是用电池供电的系统也需要这种电容。

    每10片左右的集成电路要加一片充放电电容,或称为蓄放电容,电容大小可选10uf。最好不用电解电容,电解电容是两层溥膜卷起来的,这种卷起来的结构在高频时表现为电感,最好使用胆电容或聚碳酸酝电容。

    去耦电容值的选取并不严格,可按C=1/f计算;即10MHz取0.1uf,对微控制器构成的系统,取0.1~0.01uf之间都可以。

    三、降低噪声与电磁干扰的一些经验。

    能用低速芯片就不用高速的,高速芯片用在关键地方。

    可用串一个电阻的办法,降低控制电路上下沿跳变速率。

    尽量为继电器等提供某种形式的阻尼。

    使用满足系统要求的最低频率时钟。

    时钟产生器尽量靠近到用该时钟的器件。石英晶体振荡器外壳要接地。

    用地线将时钟区圈起来,时钟线尽量短。

    I/O驱动电路尽量靠近印刷板边,让其尽快离开印刷板。对进入印制板的信号要加滤波,从高噪声区来的信号也要加滤波,同时用串终端电阻的办法,减小信号反射。

    MCD无用端要接高,或接地,或定义成输出端,集成电路上该接电源地的端都要接,不要悬空。

    闲置不用的门电路输入端不要悬空,闲置不用的运放正输入端接地,负输入端接输出端。 (10) 印制板尽量使用45折线而不用90折线布线以减小高频信号对外的发射与耦合。

    印制板按频率和电流开关特性分区,噪声元件与非噪声元件要距离再远一些。

    单面板和双面板用单点接电源和单点接地、电源线、地线尽量粗,经济是能承受的话用多层板以减小电源,地的容生电感。

    时钟、总线、片选信号要远离I/O线和接插件。

    模拟电压输入线、参考电压端要尽量远离数字电路信号线,特别是时钟。

    对A/D类器件,数字部分与模拟部分宁可统一下也不要交叉。

    时钟线垂直于I/O线比平行I/O线干扰小,时钟元件引脚远离I/O电缆。

    元件引脚尽量短,去耦电容引脚尽量短。

    关键的线要尽量粗,并在两边加上保护地。高速线要短要直。

    对噪声敏感的线不要与大电流,高速开关线平行。

    石英晶体下面以及对噪声敏感的器件下面不要走线。

    弱信号电路,低频电路周围不要形成电流环路。

    任何信号都不要形成环路,如不可避免,让环路区尽量小。

    每个集成电路一个去耦电容。每个电解电容边上都要加一个小的高频旁路电容。

    用大容量的钽电容或聚酷电容而不用电解电容作电路充放电储能电容。使用管状电容时,外壳要接地。

  • 此次活动今天结束。非常感谢大家的热情分享!!相信大家的经验会为其他使用TI MCU产品的用户提供实实在在的参考。再次感谢每位客户的参与和热心无私的分享!