zoukankan      html  css  js  c++  java
  • msp430的几个2B问题集锦

    原文地址:http://www.51hei.com/bbs/dpj-29734-1.html

    呵呵,怎么着也算是用过很久的msp430系列的单片机了,毕设用的是149,在公司用过2系列、4系列的。也算是有点经验了。想想也遇到过好多很2的问题,不知道有没有用,能想起来的就写的,有人看了可能会有帮助,也许有人会觉得这些问题都是本就该知道的或者看完后不出山人所料的感觉,那就权当小弟的一篇嬉闹之作,博君一笑而已。

    1.外设共享寄存器的问题。

    初学者经常会想不开,datesheet上明明就标着芯片里I2C、SPI、UART都有,用户手册看上去每个都是单独模块,但是事实上用起来却不是那么回事,仔细对比其寄存器,忽然发现,尼玛,他们就是一个玩意儿,而且,一次只能用一个,而而且,他们和在一起叫UART!或者usi或者usci!!而而而且,通常一款芯片只有一个UART或者usi或者usci!!也就是一次只能也仅有一个串行口可以用!!!我草,坑爹啊,TI你要不要这么无耻啊……顿时会有种菊花被人*操*弄但是又无法挣扎的感觉。
    (哦,好吧,湿太了。。。平复一下心情~~~~~~~)
    也许你这也就不能不怀疑了,为何430会这么低功耗,因为同步的I2C和SPI的主模式还有异步的UART,它们的开启都是需要时钟的,当你同时开启多个外设的时候,就会有多个时钟在工作,外设的各个寄存器分明,占用的资源也就多了,功耗自然就上去了。而430却限制你一次只能用一个,而且其寄存器非常简单,我不知道这和430的低功耗会不会真的有大的关系,但是当我使用了业内唯一敢叫板430低功耗的pic之后,居然发现它TMD也这么干。
    世界上两个半导体大公司,TI和microchip分别编织了两个谎言:低功耗和强抗干扰,诓大伙去买,然后抬高价格,其实用过的人都知道,430寄存器及其简单,外设寄存器共享,完全没有AVR和STM8那么严谨各个外设功能分明,而是能省则省。pic单片机,14位宽的程序存储器,蛋疼的ram分页,蛋疼的外设操作(特别是定时器操作,想起来头皮发麻~)……而事实上怎么样,只有用的人心里知道了,反正一个愿打一个愿挨,工程师能忍就忍,芯片厂家广告出去了,还不是挣得瓢满钵满的。。。

    2.定时器问题。

    430的定时器很给力,以前官网的选型表会写出Capture/Compare Register的个数,而弱化了Timer的概念,当然现在不会了。这个CCR是啥呢?就是捕获比较寄存器,当你看到CCR的个数有3~5个的时候,你是否很兴奋?我草,那你就悲剧了!真相就是大多数的430定时器就1个,尼玛,最普通的51都有两个!!
    最典型的CCR是有三个。一般情况下,TAR(或者TBR)是计数寄存器,它负责计数。其实说穿了也就是同步用的,当开启比较模式的时候,CCR0是被用来做周期寄存器的,而CCR1和CCR2是在CCR0的范围内与TAR(或者TBR)进行比较。其实比较一般也就是为了得到一个好的pwm模式,有了这样的一种定时器机制,寄存器简单,使用起来也很方便,可以随意更改占空比和周期,将CCR0修改即可修改周期,将CCR1或者CCR2修改即可修改占空比。定时器up模式下,产生的就是avr中所言的快速pwm,up/down模式则是相位修正pwm。虽然430定时器操作简单,但不可否认它比avr的定时器灵活得多,avr没有专门的周期寄存器,它并不能灵活的修改pwm的频率,只有在特定的几种模式下可以
    很重要的一点,430的定时器CCR的修改都是及时更新的并不像avr一样是下个周期更新或者像stm8或者stm32一样可以选择更新方式,更没有重装载寄存器。所以想要用430做spwm的朋友请注意了,如果想要得到正确的spwm波,更新CCR的时候一定要选择CCR0中断的时候
    说到中断,又有一个比较纠结的问题了,呵呵,一个定时器有两个中断向量,以TA0为例
    TIMER0_A1_VECTOR  
    TIMER0_A0_VECTOR
    TIMER0_A1_VECTOR是比较中断1~4,还有溢出中断。也就是说当不操作CCR的时候,也就是没有启用比较捕获的时候,单纯想要使用TAR计数计到0xffff溢出,会触发的中断,会进到这个中断,当然一般也就是刚从51转过来,大脑还沉浸在51快乐时光里的犯2的人才会这么做。CCR1~CCR4的比较捕获中断也是进这个中断。而CCR0是进到TIMER0_A0_VECTOR,所以做spwm的朋友要开启这个中断。一般情况下比较模式也就是PWM模式有7种,而只开启CCR0不开启其他CCR的时候,只能用四种,常用一般也就三种,set强制拉到有效,toggle扳机也就是翻转,reset强制拉到无效。

    3.ADC的功耗隐藏任务问题。

    想要低功耗,那就别用ADC,这个隐藏的功耗杀手,会不经意间给你来那么一下。当你进去深度睡眠的时候,想要测一下功耗却发现测出来的功耗与电气特性表上标明小于1uA相差了几百uA正要大骂TI坑爹的时候,你看看你的ADC关了木有~~~DC关了木有~~~C关了木有~~~关了木有~~~了木有~~~木有~~~有~~~(这是肥音)
    ADC开启的时候会消耗将近200uA的电流,和深度休眠的差了200倍!!所以最好在使用完ADC之后,将其寄存器全部清空。哦,对了,不小心插一句,AVR有硬件模拟比较器,这个默认是打开的,为了节省功耗你可以每次上电都将ACSR寄存器的ACD置位。每个使用430的ADC的孩纸上辈子都是折翼的天使,而且掉下来都是脑袋先着地的,伤不起啊~

    4.LCD外接电阻问题。
    看到这里,很多人可能都会觉得我有点吹毛求疵,不见得大家都不明白,即便这个问题也一样,说来话长估计大家都明白。那我就长话短说。很多人使用lcd的时候都喜欢在R33、R23、R13、R03之间接上大电阻,貌似为了符合用户手册上的指示,其实只是为了求心安的一个表现罢了,实际上会有多少人会把REXT置一呢?因为REXT置一才是使用外部电阻啊!!!我看过很多人的程序,没有看到啊,包括代理发给我的程序。我很负责的告诉你,你TMD就是犯贱,知道在这里加上3、4个外部电阻给你的PCB布线带来多大的烦恼么?这就是坑爹的安排!因为REXT置一之后液晶会显示不正常,这个是要调的!所以当你对于液晶对比度的调节要求要求不高的时候(Rx可以调节液晶对比度),直接将外面的电阻舍去,使用内部电阻,方便布线。
     
    5.存储器的问题。
    这个问题是一个很严肃的问题。如果说ADC是功耗的隐藏任务,那么这个就是动摇你的整个程序结构基础的隐藏boss,要么你遇不到,遇到了你就over了,因为这个不是打怪升级。我们先来看看一个warning:
    也许这个问题有人一辈子都遇不到的,这个问题很蛋疼。神马叫做访问了奇地址???这个问题和电脑上的暴力访问内存某地址有着异曲同工之妙。当时我遇到这个问题的时候,有种蛋蛋被人捏在手里的感觉。不过幸好有mc_wangbo这位高人指点。
    首先要确定这个地址在什么地方。由于430是冯诺依曼结构的所以程序存储器和数据存储器是一起的。按上用户手册上所说,0x0200以上是RAM,当然是看大小。因为当时我使用的是msp430f4152,RAM为512B,也就是0x0200~0x0400为RAM区,0x0400以上是code区,那么也就是code区有问题。
    然后再解释奇地址的问题。下面是截自用户手册的一段关于存储器组织的一段话:
     
    上面的意思是说,字节数据可以位于奇地址和偶地址,而字数据只能位于偶地址!!!什么意思呢?msp430是16位单片机,它的一个字就是2个字节,虽然它是16位单片机,它还是按照半字方式进行存储,它的一个地址对应的其实是一个字节,而不是一个字!!!也就是说它的存储方式还是8位的(这种存储方式的好处是不会浪费RAM),只是一次可以处理2个8位的数据而已...所以地址才要区分奇偶!又由于其存储方式是小端存储,16位数据高8位存在高地址低8位存在低地址,但是低地址必须是偶地址!!!
    那么情况就大概明了了。编译器编译的结果,一般单纯的指令是不会存在这种漏洞的,唯一的可能性就是,定义在code区的常量出问题了,也就是前面加了const的变量!!!
    为什么呢?因为编译器还没有那么智能,假设你定义的常量变量是一串unsigned char型的数组,带着const,如x[4]={0x12,0x34,0x56,0x78};编译器看你是定义的8位,它会使用MOV.B(半字指令)来将这串数组常量存储,假设存储在0xc120,0xc121,0xc122,0xc123这4地址上。这个本来就无可厚非,但是如果你在程序中将这4个数强制转换为一个unsigned char、一个unsigned int和一个unsigned char型的结构体(别说不可以,指针是个很奇妙的东西),那么隐藏的boss就如死神一样挥起收割灵魂的镰刀,在使用这个结构体的时候单片机先使用MOV.B来调用第一个unsigned char数也就是0xc120上的0x12,然后再用MOV.W来调用第二个unsigned inti型的数也就是0xc121和0xc122上的数连起来是0x5634,但是实际上就出错,因为低地址被存在了0xc121这个奇地址上!!!!MOV.W无法访问奇地址!!!也就是说实际上单片机根本就不会去访问0xc121这个地址,而是跳过了0xc121直接从0xc122开始取出数据,取出来的是0x7856!!!坑爹了吧!!!而且这个警告在编译的时候不会出错!!!下到单片机里面也不会出错,还能运行!!!只有在软件仿真的时候编译器会出错!!!!
    最好的解决方法,就是别这么干,编译器不会出错,它也不会故意这么分配地址,所以当你定义半字数组,而在程序中又要强制转换类型的时候,就要特别注意。如果你想要把每个数组都定义到偶地址,可以在定义完数组之后在数组后面加上@0xc120,这样数组就会定义到这个地址开始的地方。
  • 相关阅读:
    SQLServer2012数据库降级至SQLServer2008R2的方法
    男程序猿和女程序猿的网恋—相见(二)
    收藏关于AI的相关的文章
    JAVA提高九:集合体系
    JAVA提高八:动态代理技术
    JAVA提高七:类加载器
    JAVA提高六:泛型
    JAVA提高五:注解Annotation
    JAVA提高四:反射基本应用
    JAVA提高三:反射总结
  • 原文地址:https://www.cnblogs.com/guochaoxxl/p/14129132.html
Copyright © 2011-2022 走看看