极客工坊

 找回密码
 注册

QQ登录

只需一步,快速开始

查看: 68182|回复: 23

[深入浅出Energia开发第一讲]51程序的移植

[复制链接]
发表于 2012-9-11 17:16:37 | 显示全部楼层 |阅读模式
本帖最后由 水乐天 于 2012-9-12 17:50 编辑

最近听弘毅讲LaunchPad搞活动促销,超便宜,于是俺买了10块...慢慢弄总会用到滴{:soso_e154:},这几天反复折磨有一点小小心得,不敢独享,于是打算写出来与大伙分享。
  
下面放出是淘宝网店地址,注意如果数量比较多的话需要有团购代码的,需要的童鞋可以去购买:
http://item.taobao.com/item.htm?id=16603403744
----------------------------------------------------------------------------------------------------------------------------
首先声明下:本文不针对零基础的朋友,如果对一般开发常识、C语言、C++完全没有了解,请绕行。

准备工作一:
俗话说工欲善其事必先利其器,首先我们来谈谈编译环境的选择:
官方的编译环境如果没有使用过请参考《Energia介绍--MSP430的Arduino IDE》直接下载

但是官方的编译器有各种问题。。。比如中文注释不能书写。。。于是我仅用官方的编译器做调试用途,平时书写代码....还是算了吧。
我建议Windows用户选择UtralEdit IOS及Linux用户选择Sublime text 2
另外为了让我们的代码看起来更舒服 附赠代码格式化工具
----------------------------------------------------------------------------------------------------------------------------
准备工作二:
之后我们要对手头的LaunchPad做些小小的处理:

第一步 将RXD与TXD 两个跳线横过来,因为串口输出到PC需要这两个端口,否则无法进行串口输出。
第二步 将P1.6和P1.0两个LED等的跳线拔掉,因为这两个端口跟I2C端口冲突,所以在调试的时候如果你不需要这两个LED最好将其拔掉。
第三步 注意如果你的程序要使用串口的话,那么3号和4号引脚尽量不要使用,否则会影响串口数据的输出。
为了让大家更清楚地了解,如下图所示:

----------------------------------------------------------------------------------------------------------------------------
1.1 首先让我们来看一个51的程序。
   本人本行是开发上位系统软件基本是硬件盲,在写这个之前完全没接触过51单片机,也没写过51的程序,各位硬件高手不要见笑哈。但是我觉得从太简单的程序入手没意思哈,于是从公司同事手中借来个台湾燃太的TN901红外温度传感器和51的范例程序。于是我们就拿这个程序开始我们的改造好了。如下图所示:

     因为51的完整代码比较长还包括LCD的显示,所以我们摘主要的来看,想看完整代码点下载   
     主要我们需要转换的部分的包括这几个部分
   一、端口定义:
  1. sbit TN_Data = P1^0; //定义TN9接口
  2. sbit TN_Clk  = P1^2;
  3. sbit TN_ACK  = P1^4;
复制代码


   二、主程序部分:

  1. /*----------------------------------主程序入口-----------------------------------*/
  2. void main()
  3. {
  4.     LCD_Init();      //LCD初始化
  5.     Delay5Ms();
  6.     LCD_Write_String(0, 0, Range);
  7.     LCD_Write_String(0, 1, table);
  8.     Delay400Ms();
  9.     TN_ACK = 1;
  10.     while(1)
  11.     {

  12.         TN_ACK = 0;
  13.         TN_ReadData(0x4c);                //目标温度的第一个字节为0x4c

  14.         if((ReadData[0] == 0x4c) && (ReadData[4] == 0x0d))   //每帧的最后一个字节为0x0d
  15.         {
  16.             TN_GetData_Target();
  17.         }

  18.         DelayMs(1);

  19.         TN_ACK = 0;
  20.         TN_ReadData(0x66);                //环境温度的第一个字节为0x66

  21.         if((ReadData[0] == 0x66) && (ReadData[4] == 0x0d)) //每帧的最后一个字节为0x0d
  22.         {
  23.             TN_GetData_Temp();
  24.         }
  25.     }
  26. }
复制代码


   三、IIC接口数据传输:
  1. void TN_ReadData(uchar flag)        //读数据
  2. {
  3.     uchar i,j,k;
  4.         bit BitState = 0;                                        //每次发七帧
  5.         for(k=0;k<7;k++)
  6.         {
  7.                     for(j=0;j<5;j++)                           //每帧5个字节
  8.                  {
  9.                     for(i=0;i<8;i++)
  10.                         {
  11.                            while(TN_Clk);
  12.                            BitState= TN_Data;
  13.                            ReadData[j]= ReadData[j]<<1;
  14.                            ReadData[j]= ReadData[j]|BitState;
  15.                            while(!TN_Clk);

  16.                         }
  17.                  }

  18.                  if(ReadData[0]==flag)  k=8;
  19.         }

  20.         TN_ACK=1;
  21. }
复制代码

     虽然我从没写过51的程序,但是我觉得大体上51程序结构都应该差不多,所以我按照这种方法来转换就好,这个程序搞定了基本其它程序也类似如此。
   首先我们来转换,第一部分端口的定义,51这里用的类型是sbit,对应应该是byte 0或1 估计是标识每个端口的高低电平,但是我们这里与51程序的含义不同应该标识具体的端口号,所以我们这里采用int类型,如下所示:
  
  1.     int  TN_Data=7;
  2.     int TN_Clk=8;
  3.     int TN_ACK=9;
复制代码

     之后我们来看程序的入口函数,注意这里的端口值改变比如 TN_ACK=1; (51代码原来很精简哦)其实是给ACK端口赋值为高电平,所以我们这里应该对应的写法是
  1. pinMode(TN_ACK, OUTPUT);//指定ACK引脚为输出脚
  2.   digitalWrite(TN_ACK,HIGH);//将指定端口输出为高电平
复制代码

     为了处理方便我们将51主方法中的代码分割在Setup和Loop方法中执行于是,我们将其分割为两个部分,将初始化部分放在Setup中执行,While(1)中的部分放在Loop中执行,如下所示:
  1. //初始化部分
  2. void setup()
  3. {
  4.     pinMode(TN_Clk, INPUT);   //设定时钟口为输入端口
  5.     pinMode(TN_ACK, OUTPUT);  //设定ACK口为输出端口
  6.     digitalWrite(TN_ACK,HIGH);//在ACK口输出高电平
  7. }

  8. //采集部分
  9. void loop()
  10. {
  11.    digitalWrite(TN_ACK,LOW);
  12.    TN_ReadData(0x4c);                          //目标温度的第一个字节为0x4c   
  13.    if((ReadData[0]==0x4c)&&(ReadData[4]==0x0d))//每帧的最后一个字节为0x0d   
  14.    {   
  15.       Target=TN_GetData_Target();   
  16.    }
  17.                   
  18.    delay(1);
  19.          
  20.    digitalWrite(TN_ACK,LOW);
  21.    TN_ReadData(0x66);                          //环境温度的第一个字节为0x66      
  22.   
  23.    if((ReadData[0]==0x66)&&(ReadData[4]==0x0d))//每帧的最后一个字节为0x0d   
  24.    {   
  25.        Temp=TN_GetData_Temp();
  26.    }
  27. }
复制代码


然后我们来看IIC数据传输的部分,大体逻辑我是这样理解的,时钟作为一个标志位,每当时钟高低电平改变的时候采用将1字节的数据存储起来并左移一位,直到出现结束标志位为止,这里我们要注意下51程序中while(TN_Clk);这样的地方。在这里我们TN_Clk代表的不是具体端口的高低电平所以要换成这样的写法
  1. while(val)
  2.                 {
  3.                     val = digitalRead(TN_Clk);//获取端口的高低电平
  4.                 }
复制代码

之后我们把这部分的代码转换过来,如下所示:
  1. void TN_ReadData(char flag)        //读数据
  2. {
  3.     char i, j, k;
  4.     byte BitState = 0;                                        //每次发七帧
  5.     for(k = 0; k < 7; k++)
  6.     {
  7.         for(j = 0; j < 5; j++)                         //每帧5个字节
  8.         {
  9.             for(i = 0; i < 8; i++)
  10.             {
  11.                 int val = digitalRead(TN_Clk);//注意这里51是直接读端口号所以我们要进行转换
  12.                 while(val)
  13.                 {
  14.                     val = digitalRead(TN_Clk);
  15.                 }
  16.                 BitState = digitalRead(TN_Data);
  17.                 ReadData[j] = ReadData[j] << 1;
  18.                 ReadData[j] = ReadData[j] | BitState;
  19.                 while(!val)
  20.                 {
  21.                     val = digitalRead(TN_Clk);
  22.                 }
  23.             }
  24.         }

  25.         if(ReadData[0] == flag)  k = 8;
  26.     }

  27.     digitalWrite(TN_ACK, HIGH);
  28. }
复制代码


再给这个程序加上串口输出的部分,我们这次的内容就大功告成了:)
  1. int TN_Data = 15;
  2. int TN_Clk = 14;
  3. int TN_ACK = 13;
  4. unsigned char  ReadData[5];
  5. short Temp,Target;

  6. void setup()
  7. {
  8.     Serial.begin(9600);
  9.     pinMode(TN_Clk, INPUT);//
  10.     pinMode(TN_ACK, OUTPUT);
  11.     digitalWrite(TN_ACK,HIGH);
  12. }

  13. void loop()
  14. {
  15.    digitalWrite(TN_ACK,LOW);
  16.    TN_ReadData(0x4c);                //目标温度的第一个字节为0x4c   
  17.    if((ReadData[0]==0x4c)&&(ReadData[4]==0x0d))         //每帧的最后一个字节为0x0d   
  18.    {   
  19.       Target=TN_GetData_Target();   
  20.    }
  21.                   
  22.    delay(1);
  23.          
  24.    digitalWrite(TN_ACK,LOW);
  25.    TN_ReadData(0x66);                //环境温度的第一个字节为0x66      
  26.   
  27.    if((ReadData[0]==0x66)&&(ReadData[4]==0x0d))    //每帧的最后一个字节为0x0d   
  28.    {   
  29.        Temp=TN_GetData_Temp();
  30.    }
  31. }

  32. void SerialValue()
  33. {
  34.    Serial.print("Target: ");
  35.    Serial.print(Target, DEC);
  36.    Serial.println(" C");
  37.    Serial.print("Temp: ");
  38.    Serial.print(Temp, DEC);
  39.    Serial.println(" C");
  40. }

  41. void TN_ReadData(char flag)        //读数据
  42. {
  43.         char i,j,k;
  44.         byte BitState = 0;                                        //每次发七帧
  45.         for(k=0;k<7;k++)
  46.         {
  47.                     for(j=0;j<5;j++)                           //每帧5个字节
  48.                  {
  49.                     for(i=0;i<8;i++)
  50.                         {
  51.                            int val= digitalRead(TN_Clk);
  52.                            while(val)
  53.                            {
  54.                                val = digitalRead(TN_Clk);
  55.                            }
  56.                            //val = digitalRead(TN_Clk);
  57.                            BitState= digitalRead(TN_Data);
  58.                            ReadData[j]= ReadData[j]<<1;
  59.                            ReadData[j]= ReadData[j]|BitState;
  60.                           while(!val)
  61.                           {
  62.                               val = digitalRead(TN_Clk);
  63.                           }
  64.                         }
  65.                  }

  66.                  if(ReadData[0]==flag)  k=8;
  67.         }

  68.         digitalWrite(TN_ACK,HIGH);
  69. }

  70. int TN_GetData_Temp()   
  71. {   
  72.     int Temp;   
  73.     Temp=(ReadData[1]<<8)|ReadData[2];   
  74.     Temp = (float)Temp/16 - 273.15;   
  75.     Temp=Temp*100;                               //温度值乘100,以方便计算小数点后两位   
  76.    
  77.     return Temp;
  78. }   

  79. int TN_GetData_Target()   
  80. {   
  81.     int Target;   
  82.     Target=(ReadData[1]<<8)|ReadData[2];   
  83.     Target = (float)Target/16 - 273.15;   
  84.     Target=Target*100;                               //温度值乘100,以方便计算小数点后两位   
  85.    
  86.     return Target;
  87. }
复制代码



最后我们来总结下51到Arduino程序转换需要注意的地方:

第一:端口定义的转换,因为端口取值的方式不同所以写法上要转换下,个人觉得从设计模式的角度上讲,51的端口取值方式虽然很方便,但是容易造成变量定义时的混淆,有时候多写几行代码未必是坏事。

第二:因为Arduino的基本结构包含Setup和Loop,51这里一般用一个死循环直接实现。所以这里要注意下程序哦分割。

第三:注意效率问题,比如Serial输出这样的方法消耗一定的时间,一次可能影响很小,但是如果套在多层循环中和需要速度的处理中影响会很大。有兴趣的朋友可以试试把串口输出的实际时间消耗。最后把程序模块化分割,冗余的逻辑。

其他方面我觉得程序移植起来还是很方便的,基本大部分51的代码都可以用Arduino来实现。本次因为这是测试代码所以有些小乱,我将会在后面的文章中详细讲解下如何整理和封装代码的步骤,让大家写起程序更加模块化:)

本帖子中包含更多资源

您需要 登录 才可以下载或查看,没有帐号?注册

x

评分

参与人数 1 +1 收起 理由
幻生幻灭 + 1 神马都是浮云

查看全部评分

回复

使用道具 举报

发表于 2012-9-11 17:28:31 | 显示全部楼层
买10块干吗用~?
回复 支持 反对

使用道具 举报

发表于 2012-9-11 20:03:59 | 显示全部楼层
性能到底如何?好像是32K的处理器?好像到处都没说详细硬件性能啥的;
还是ARDUINO描述全面
回复 支持 反对

使用道具 举报

发表于 2012-9-11 20:10:25 | 显示全部楼层
外部晶震32K的,好像是16K的混合信号微控制器。。。具体能做什么还是不太懂。。。哎~~~~
看百度介绍控制器的说明好像主要还是低成本的数据采集处理
回复 支持 反对

使用道具 举报

发表于 2012-9-11 20:13:47 | 显示全部楼层
不错啊,我好想买的
回复 支持 反对

使用道具 举报

发表于 2012-9-11 23:20:24 | 显示全部楼层
不知道51的代码移植的效果如何,其实51应该是单片机比较入门的普及型机,很多大学的计算机系MSC51和Z80都是必修的专业课。。。
都能移植应该很强大了,而且这个东东貌似比51更强大?
回复 支持 反对

使用道具 举报

 楼主| 发表于 2012-9-11 23:31:19 | 显示全部楼层
本帖最后由 水乐天 于 2012-9-11 23:32 编辑

是的哈51的代码应该理论上都可以移植,这个东西普及了基本51市场就很小了:)我觉得用Arduino开发的最大好处是可以让新手和专家在开发时专注业务逻辑。
回复 支持 反对

使用道具 举报

发表于 2012-9-12 08:57:20 | 显示全部楼层
darkorigin 发表于 2012-9-11 20:03
性能到底如何?好像是32K的处理器?好像到处都没说详细硬件性能啥的;
还是ARDUINO描述全面

16M内部振荡器
回复 支持 反对

使用道具 举报

发表于 2012-9-12 08:57:39 | 显示全部楼层
darkorigin 发表于 2012-9-11 20:10
外部晶震32K的,好像是16K的混合信号微控制器。。。具体能做什么还是不太懂。。。哎~~~~
看百度介绍控制器 ...

16M........不是K......
回复 支持 反对

使用道具 举报

发表于 2012-9-12 08:57:58 | 显示全部楼层
darkorigin 发表于 2012-9-11 23:20
不知道51的代码移植的效果如何,其实51应该是单片机比较入门的普及型机,很多大学的计算机系MSC51和Z80都是 ...

MCS51弱爆了
回复 支持 反对

使用道具 举报

发表于 2012-9-12 18:07:35 | 显示全部楼层
这个要顶~  写得太详细了,对于初学launchpad,用Arduino开发的人来说太有用了!图文并茂,工具下载链接,程序代码及注释,注意事项,神马都有了,哈哈~~   向LZ学习!
回复 支持 反对

使用道具 举报

发表于 2012-9-12 20:15:27 | 显示全部楼层
┏ωǒ┛菰独 发表于 2012-9-12 08:57
MCS51弱爆了

确实MSC51很弱。但是51系列单片机貌似是出货量和存世量都很大的控制器。
代码神马的也都很经典啊。包括89c52啥的 也都是大量被应用的。
弱主要在性能上,但是强在便宜,毕竟周边元件也少,做一些简单应用完全够了,比如计算器,比如定时装置,比如其他设备的周边(比如显示模块的控制电路)也够了。

这个主控能移植51代码那么代码量上和例程上基本上真的是很广阔啊。。。哇咔咔

性能到底如何呢?16M的内部震荡,好像外部震荡频率还支持更高的?
回复 支持 反对

使用道具 举报

发表于 2012-9-12 20:16:02 | 显示全部楼层
┏ωǒ┛菰独 发表于 2012-9-12 08:57
16M........不是K......

额。呵呵 手误。哈哈~~~SORRY
回复 支持 反对

使用道具 举报

发表于 2012-9-12 20:16:58 | 显示全部楼层
┏ωǒ┛菰独 发表于 2012-9-12 08:57
MCS51弱爆了

Z80好像还要弱。 现在好像没有看到神马产品了
回复 支持 反对

使用道具 举报

发表于 2012-9-12 20:24:20 | 显示全部楼层
水乐天 发表于 2012-9-11 23:31
是的哈51的代码应该理论上都可以移植,这个东西普及了基本51市场就很小了:)我觉得用Arduino开发的最大好处 ...

是的,其实这也是程序设计的潮流,逐渐的通过强化IDE界面简化编程难度,使得程序员更多精力不会被牵制在那些冗余简单的代码上(比如C++ 和VC++ 到C# )不用自己画界面而采用组件的方式编程(当年TC2.0的时候UCDOS带的几个画图的例程和库文件我学了几个礼拜)
更多的让程序员去强化功能和逻辑(算法)上。
记得当年学MSC51时候 神马 基址变址寄存器 神马的搞死人了 用了C去做单片编程就已经是个里程碑(至少省略了初始化的几个堆栈操作)
回复 支持 反对

使用道具 举报

您需要登录后才可以回帖 登录 | 注册

本版积分规则 需要先绑定手机号

Archiver|联系我们|极客工坊

GMT+8, 2024-3-29 00:49 , Processed in 0.058982 second(s), 26 queries .

Powered by Discuz! X3.4 Licensed

Copyright © 2001-2021, Tencent Cloud.

快速回复 返回顶部 返回列表