实现一个简单的msp430软件

以做一个简单的采集设备为例。假定已经准备好硬件设备,现在我们开始在MCU上搭建运行的软件。

使用的软件为iar ew430 5.10b,仿真器是杭州利尔达的USB型MSP430仿真器LSD-FET430 UIF,晶振源为8Mhz。

开发环境

第一步 新建一个项目,projiect->new project

实现一个简单的msp430软件_第1张图片
new project

确定后会提示输入项目名称保存位置等,按照提示填写完毕后,一个空的项目就建立成功了。

实现一个简单的msp430软件_第2张图片
新的空白项目

对项目的属性进行设置,以便可以进行正常的调试

实现一个简单的msp430软件_第3张图片
设置MCU芯片
实现一个简单的msp430软件_第4张图片
设置堆栈

实现一个简单的msp430软件_第5张图片
设置连接文件的位置

图中的连接文件直接放在了项目文件夹下所以这样设置,也可以使用默认设置。
如果需要改变段的大小的话,就需要对xcl文件进行修改。
因此最好将xcl文件放在项目文件夹下这样有助于定制化
xcl文件在IAR的安装地址的config文件夹下

实现一个简单的msp430软件_第6张图片
xcl文件放置的位置
实现一个简单的msp430软件_第7张图片
设置hex文件格式 后期远程升级会用到
实现一个简单的msp430软件_第8张图片
输出文件

实现一个简单的msp430软件_第9张图片
设置Debug方式

Debug有两种方式,一种是软件模拟调试,还有一种是JTAG调试

实现一个简单的msp430软件_第10张图片
设置烧写方式

第二步开始code吧

任何软件都是从main函数开始,那我们就建一个main.c文件。
项目目的主要是完成数据采集,需要使用AD采集和UART。
首先为项目添加头文件,新建一个include.h文件,填入需要加入的头文件

实现一个简单的msp430软件_第11张图片
新建文件
#include "msp430x54xa.h"
#include "string.h"

使用类似方法新建其他的头文件如datatypedef.h --数据定义&globalvar.h--全局变量
在include.h中添加新的头文件

#include "msp430x54xa.h"
#include "datatypedef.h"
#include "globalvar.h"
#include "string.h"

新建main.c文件,加入如下内容

#include "include.h"
void main()
{
  //硬件初始化
  InitSys( );
  
 //FlashWrite_seg((UCHAR *)0xAc00 , UartBuffer0 , 490 );
  WDT_CLR;
//配置io口,内部模块
  ConfigGpio();
  
  uart_a0setup(3);//和sim1模块通讯,控制sim1
  uart_a1setup(3);//和sim1模块通讯,控制sim1
  uart_a2setup(3);//和PC通讯,用于调试
  uart_a3setup(3);//用于和程控放大电路通讯
  Timera0Config();//定时器,10ms周期
  _EINT();
  while(1);
}

这里面一些硬件初始化的函数还未定义,因此我们新建一个专门定义硬件初始化的文件,命名为device.c,填入如下内容

#include "include.h"

#include "string.h"

//==============================================================================
/*系统时钟配置,SMCLK = MCLK = 8M,ACLK = REFCLOCK = 32768*/
//==============================================================================
void InitSys( )
{
  U_INT num = 0 ;
////////////////////////////////////////////////////////////////////////////////////////////////////////////////  
///设置基本时钟/////////////////////////////////////////////////////////////////////////////////////////////////
  WDTCTL = WDTPW + WDTHOLD;                 // 关闭看门狗

  P11DIR = BIT1 + BIT2 ;                    // P11.1-2 to output direction
  //P11SEL = BIT1 + BIT2 ;                    // P11.1-2 to output SMCLK,MCLK
  P5SEL  = BIT2 + BIT3 ;                           // Port5.2 5.3 select XT2 ,5.0 5.1 selectBIT0 ++ BIT1 + BIT3  
                                          // for ref Vcc
  UCSCTL6 &= ~XT2OFF;                       // 使能XT2【高频晶振】
 // UCSCTL6 |= XT2BYPASS ;                    //
  UCSCTL3 |= SELREF_2;                      // FLLref = REFO
                                            // Since LFXT1 is not used,
                                            // sourcing FLL with LFXT1 can cause
                                            // XT1OFFG flag to set
  UCSCTL4 |= SELA_2;                        // ACLK=REFO,SMCLK=DCO,MCLK=DCO

  // Loop until XT1,XT2 & DCO stabilizes
  do
  {
    UCSCTL7 &= ~(XT2OFFG + XT1LFOFFG + XT1HFOFFG + DCOFFG);
                                            // Clear XT2,XT1,DCO fault flags
    SFRIFG1 &= ~OFIFG;                      // Clear fault flags
    
    for( num = 0xFF ; num > 0 ; num -- ) ;
  }while (SFRIFG1&OFIFG);                   // Test oscillator fault flag

  UCSCTL6 &= ~( XT2DRIVE0 + XT1DRIVE0 ) ;   // Decrease XT2 Drive according to
  //UCSCTL5 |= DIVM__0 + DIVS__0;                                          // expected frequency
  //重新配置MCLK和SMCLK为高频时钟,8MHz
  UCSCTL4 |= SELS_5 + SELM_5;               // SMCLK=MCLK=XT2,ACLK=REF
  
}
void InitGpio()
{
  PASEL = 0;
  PBSEL = 0;
  PCSEL = BIT2+BIT3+BIT0;
  PDSEL = 0;
  PESEL = 0;
  PFSEL = 0;
 // PGSEL = 0;
    PAOUT = 0;
  PBOUT = 0;
  P4OUT |= BIT0;
  PCOUT = 0;
  PDOUT = 0;
  P8OUT |= BIT3;
  PEOUT = 0;
  PFOUT = 0;
  PADIR = 0xFFFF;
  PBDIR = 0xFFFF;
  PCDIR = 0xFFFF;
  PDDIR = 0xFFFF;
  P9DIR = 0xFF;
  PFDIR = 0xFFFF;
  

  
  PAIE = 0;

}
//初始化系统IO口控制,

void ConfigGpio()
{
  P1SEL |= BIT1;
  InitGpio();
    SIM_BATOFF_1;
  SIM_BATOFF_2;
  CHARGE_OFF;
  P2DIR &= ~( BIT5 );//  BIT5,BIT6 (SIM_0 SIM_1)设置为输入状态
  P3DIR = BIT4+BIT5 ;//0:sd en and  6:CAMERA POW EN 7:ALTRASONIC POW EN
  P5DIR = BIT6+BIT7;
  P8DIR &= ~BIT2  ;//
  //P3DIR = BIT0 ; //FM CS CONTROL
  P4DIR &= ~BIT3 ;//comm (2010-10-13) power en
  P4DIR |=BIT6;//控制红外灯;
  P4OUT |=BIT6;//初始化关闭红外灯;
  
  P1DIR = BIT3 + BIT4 + BIT5 + BIT6+ BIT7;          //3: mcu3 to mcu1 require 4:初始状态0,1兼可 mcu3 to mcu1 status 
  P7DIR = BIT2 ;   //com1 power en
  
  
 // P1IES |= 0x01 ;         //mcu1 to mcu2 pps input,下降沿触发中断
  P10DIR |= BIT6;
  P10OUT |= BIT6;
  P10DIR &= ~BIT4;
  P9DIR &= ~BIT3;
  P6SEL |= 0XF;
  P2DIR |= BIT1+BIT2+BIT3;
  P2OUT &=0xF1;
  //
  

 
}



///////////////////////////////////////////
/////异步串口0设置:br=1(4800)       //////
/////br=2(9600);br=3(115200)         //////
///////////////////////////////////////////
void uart_a0setup( UCHAR br )         
{
  P3SEL |= BIT5 +BIT4 ;
  
  UCA0CTL1 |= UCSWRST ;                     // **Put state machine in reset**
  UCA0CTL1 |= UCSSEL1 ;                     // SMCLK
  switch( br )
  {
  case 1:
    UCA0BRW = 104;                          // 8MHz 4800 (see User's Guide)
    UCA0MCTL = UCBRS_0 + UCBRF_3 + UCOS16;  // Modln UCBRSx=0, UCBRFx=3,
    break;
  case 2:
    UCA0BRW =  52;                           // 8MHz 9600 (see User's Guide)
    UCA0MCTL = UCBRS_0 + UCBRF_1 + UCOS16;  // Modln UCBRSx=0, UCBRFx=1,
    break;
  case 3:
    UCA0BRW = 69;                           // 8MHz 115200 (see User's Guide)
    UCA0MCTL = UCBRS_4 + UCBRF_0 ;          // Modln UCBRSx=4, UCBRFx=0,
    break;
  default:
    UCA0BRW = 52;                           // 8MHz 9600 (see User's Guide)
    UCA0MCTL = UCBRS_0 + UCBRF_1 + UCOS16;  // Modln UCBRSx=0, UCBRFx=1,
    break;
  }

  UCA0CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
  UCA0IE |= UCRXIE ;
 
  
}

///////////////////////////////////////////
/////异步串口1设置:br=1(4800)       //////
/////br=2(9600);br=3(115200)         //////
///////////////////////////////////////////
void uart_a1setup( UCHAR br )         
{
  P5SEL |= BIT6 +BIT7 ;
  //UCA1CTL0 |= UCMSB;
  UCA1CTL1 |= UCSWRST ;                     // **Put state machine in reset**
  UCA1CTL1 |= UCSSEL1 ;                     // SMCLK
  switch( br )
  {
  case 1:
    UCA1BRW = 104;                          // 8MHz 4800 (see User's Guide)
    UCA1MCTL = UCBRS_0 + UCBRF_3 + UCOS16;  // Modln UCBRSx=0, UCBRFx=3,
    break;
  case 2:
    UCA1BRW = 52;                           // 8MHz 9600 (see User's Guide)
    UCA1MCTL = UCBRS_0 + UCBRF_1 + UCOS16;  // Modln UCBRSx=0, UCBRFx=1,
    break;
  case 3:
    UCA1BRW = 69;                           // 8MHz 115200 (see User's Guide)
    UCA1MCTL = UCBRS_4 + UCBRF_0 ;          // Modln UCBRSx=4, UCBRFx=0,
    break;
  default:
    UCA1BRW = 52;                           // 8MHz 9600 (see User's Guide)
    UCA1MCTL = UCBRS_0 + UCBRF_1 + UCOS16;  // Modln UCBRSx=0, UCBRFx=1,
    break;
  }
  UCA1CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
  UCA1IE |= UCRXIE ;
 

}


///////////////////////////////////////////
/////异步串口2设置:br=1(4800)       //////
/////br=2(9600);br=3(115200)         //////
///////////////////////////////////////////
void uart_a2setup( UCHAR br )         
{
  P9SEL |= BIT5 +BIT4 ;
 // UCA2CTL0 |= UCMSB;
  UCA2CTL1 |= UCSWRST ;                     // **Put state machine in reset**
  UCA2CTL1 |= UCSSEL1 ;                     // SMCLK
  switch( br )
  {
  case 1:
    UCA2BRW = 104;                          // 8MHz 4800 (see User's Guide)
    UCA2MCTL = UCBRS_0 + UCBRF_3 + UCOS16;  // Modln UCBRSx=0, UCBRFx=3,
    break;
  case 2:
    UCA2BRW = 52;                           // 8MHz 9600 (see User's Guide)
    UCA2MCTL = UCBRS_0 + UCBRF_1 + UCOS16;  // Modln UCBRSx=0, UCBRFx=1,
    break;
  case 3:
    UCA2BRW = 69;                           // 8MHz 115200 (see User's Guide)
    UCA2MCTL = UCBRS_4 + UCBRF_0 ;          // Modln UCBRSx=4, UCBRFx=0,
    break;
  case 4:
    UCA2BRW = 138;
    UCA2MCTL = UCBRS_7 + UCBRF_0;
    break;
  default:
    UCA2BRW = 52;                           // 8MHz 9600 (see User's Guide)
    UCA2MCTL = UCBRS_0 + UCBRF_1 + UCOS16;  // Modln UCBRSx=0, UCBRFx=1,
    break;
  }
  UCA2CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
  UCA2IE |= UCRXIE ; ;
 

}

///////////////////////////////////////////
/////异步串口3设置:br=1(4800)       //////
/////br=2(9600);br=3(115200)         //////
///////////////////////////////////////////
void uart_a3setup( UCHAR br )         
{
  P10SEL |= BIT5 +BIT4 ;
 // UCA3CTL0 |= UCMSB;
  UCA3CTL1 |= UCSWRST ;                     // **Put state machine in reset**
  UCA3CTL1 |= UCSSEL1 ;                     // SMCLK
  switch( br )
  {
  case 1:
    UCA3BRW = 104;                          // 8MHz 4800 (see User's Guide)
    UCA3MCTL = UCBRS_0 + UCBRF_3 + UCOS16;  // Modln UCBRSx=0, UCBRFx=3,
    break;
  case 2:
    UCA3BRW = 52;                           // 8MHz 9600 (see User's Guide)
    UCA3MCTL = UCBRS_0 + UCBRF_1 + UCOS16;  // Modln UCBRSx=0, UCBRFx=1,
    break;
  case 3:
    UCA3BRW = 69;                           // 8MHz 115200 (see User's Guide)
    UCA3MCTL = UCBRS_4 + UCBRF_0 ;          // Modln UCBRSx=4, UCBRFx=0,
    break;
  case 4:
    UCA3BRW = 32;                           // 8MHz 115200 (see User's Guide)
    UCA3MCTL = UCBRS_4 + UCBRF_0 ;          // Modln UCBRSx=4, UCBRFx=0,
    break;
  default:
    UCA3BRW = 52;                           // 8MHz 9600 (see User's Guide)
    UCA3MCTL = UCBRS_0 + UCBRF_1 + UCOS16;  // Modln UCBRSx=0, UCBRFx=1,
    break;
  }
  UCA3CTL1 &= ~UCSWRST;                     // **Initialize USCI state machine**
  UCA3IE |= UCRXIE ; ;
  // COM3IEON ;
}

//==============================================================================
//===========================TimerA0作为延时计数时钟设置 ===========================
//===========================中断周期10ms========================================
//===========================增模式,采用SMCLK作为输入时钟源====================
//==============================================================================
void Timera0Config()
{
  TA0CTL = TASSEL1 + TACLR + TAIE + ID1 + ID0 ; //8M频率,8分频,输入时钟为1Mhz 
  TA0CCR0 = 10000-1 ; //定义定时器A存储器的值,使输出频率f=f_ACLK/(N*TACCR0),N为分频数=1; ////////////////
  TA0CTL |= MC__UP ;  //定时器开关            */             //////////////////////////////////////////////////
  /////////////////////////////////////////////////////// ////////////////////////////////////////////
}

接着我们需要将这两个文件加到项目中去。

实现一个简单的msp430软件_第12张图片
添加文件
实现一个简单的msp430软件_第13张图片
添加完之后

接着我们编译一下看看能不能成功?

实现一个简单的msp430软件_第14张图片
捕获_副本.png
实现一个简单的msp430软件_第15张图片
编译信息

哈哈,成功了。少量的warning可以忽略,不影响软件的运行。

但这仅仅是可以下载到MCU中去,硬件配置基本完成,但是还没有实际的功能。那现在就给他加点功能吧。
由于是采集设备,那么我们先实现基本的AD采集吧。
在device.c中加入对AD寄存器的配置函数void ConfigAdc(),以及它的采样时钟源的配置void TimerbConfig()。
ad采集开始和结束的函数void AdcStart()&void AdcStop(),
串口发送数据的函数void Com2TxChar( UC a )&void txtoPC(UC* P1,UI P2)
软件使用内部看门狗复位的函数void WdtReset()

//配置AD采集模块
void ConfigAdc()
{
  P6SEL = 0xff ;                            //设置AD采集输入管脚A0~A7
 // P6SEL &= ~BIT4;
//  P7SEL |= 0XF0 ;                           //A12~A15
  P5SEL |= BIT0 + BIT1;                    //设置采集参考电压输入管脚
  ADC12CTL0 &= ~ADC12ENC ;                  //关闭AD使能
  ADC12CTL0 = ADC12ON + ADC12SHT0_8 +ADC12MSC ;//打开AD采集模块内核  //去掉“+ ADC12REFON ” jmj 2011.03.12  
  ADC12CTL1 = ADC12SSEL1 + ADC12CONSEQ_3 + ADC12CSTARTADD_0 + ADC12SHS_3 ;
                                            //时钟MCLK,多通道连续采集,开始地址A0,TimerB触发
  ADC12CTL2 = ADC12TCOFF + ADC12RES1 + ADC12SR ;//温度传感器关闭,12bit AD 低采样率<50k
  ADC12MCTL0 = ADC12SREF_0 + ADC12INCH_0  ;  //外部电压参考,A0通道
  ADC12MCTL1 = ADC12SREF_0 + ADC12INCH_1 ;  //外部电压参考,A1通道
  ADC12MCTL2 = ADC12SREF_0 + ADC12INCH_2 ;  //外部电压参考,A2通道
  ADC12MCTL3 = ADC12SREF_0 + ADC12INCH_3 ;  //外部电压参考,A3通道
  ADC12MCTL4 = ADC12SREF_0 + ADC12INCH_4;  //外部电压参考,A4通道[采集温度传感器的值]
  ADC12MCTL5 = ADC12SREF_0 + ADC12INCH_5 ;  //外部电压参考,A5通道
  ADC12MCTL6 = ADC12SREF_0 + ADC12INCH_6 ;  //外部电压参考,A6通道
  ADC12MCTL7 = ADC12SREF_0 + ADC12INCH_7 + ADC12EOS ;  //外部电压参考,A7通道,时序采样结束
  ADC12IE = 0X0080 ;                        //打开通道7的中断
  ADC12CTL0 |= ADC12ENC ;                   //打开AD使能
 // ADC12CTL0 |= ADC12SC ;                    //SHP = 0,ADC12SC保持高电平            
  
}
//==========timerb被设置为AD采集采样率==========================================
//==========freq,设定的采样率的值。============================================
//==========增模式,不使能中断,采用SMCLK作为时钟源=============================
//==============================================================================
void TimerbConfig()
{
 
  TBCCTL0 = 0;
  TBCCTL1 = 0;
  TBCTL = TBSSEL1 + TBCLR ;//8MHz jmj 2011.03.30 //+ ID0 + ID1;//8Mhz,8分频 1MHz;2010-10-14
                                     // +ID0 + TBIE   //////////////////// 1分频,4M
  
  /////定时器TB1为比较器为采集触发频率//////////////
  TBCCTL1 |= OUTMOD_3 ;// ; +CCIE/* //TimerB1 比较器设置///////////////////*/
  TBCCR1 = 555;       
  TBCCR0 = 999 ;                    
  TBCTL |= MC__UP ;                  //启动TimerB,增计数模式,由于提供采样率,
                                      //不使能中断
  
  //////////////////////////////////////////////////////////////////
}
//
void AdcStart()
{

   UI i;
   for(i=0;i

增加中断函数文件 isr.c,内容如下,主要实现了ADC中断 AdcIsr(void)和定时器中断ten_ms_TimerIsr(void)。

#include "include.h"
#include "string.h"


#pragma vector = ADC12_VECTOR
__interrupt void AdcIsr(void)
{
  int temp, i;
  ADC12IFG = 0;
  static UI temp_volt0=0;
  static UI temp_volt1= 0;
  UL temp_df=0L;
  
   if(SendDataCnt < SendPeriod)
   {
     if((AdcCnt++) < (1000*60))
       {
          Data[SendDataCnt]+= abs(ADC12MEM0-2048);
          
       }
  
     else
      {
         AdcCnt = 0;
   
      
         temp_volt0 += ADC12MEM1;
         temp_volt1 += ADC12MEM2;
         DJ_state=1;
         
          SendDataCnt++;
           
       }
   }
    else
    {
      
      BatVolt = temp_volt0/SendPeriod;
      ChargeVolt = temp_volt1/SendPeriod;
      temp_volt0=0;
      temp_volt1=0;
      SendDataCnt = 0;
      NeedSendData = 1;
      //GprsLinkDelay = MAX_LINK_DELAY;
     // AdcStop();
      LPM0_EXIT;
      
    }                        
  }

#pragma vector = TIMER0_A1_VECTOR
__interrupt void ten_ms_TimerIsr(void)
{  
  
  static UC msCounter=0;
  
  static UC ledcounter = 5;
  UC temp4[4];
  TA0CTL &= ~TAIFG;
  
 
  WDT_CLR;
  WDT1_CLR;
 
  //----------------------------
   if(msCounter<100)
   {
      msCounter++;
      
   }
  else 
  {
      msCounter=0;
      if(ledcounter){
        ledcounter--;
    
      }
      
      secondCounter++;
      if(secondCounter == 0x3840)
      {
         secondCounter = 0;
        
          WdtReset();//循环,等待看门狗复位
          while(1);
        
      }
     
  }
  

}

主函数main.c中增加了开始采集,以及采集两分钟后,通过串口通知上位机已经采集完一个周期的数。

SendPeriod = 1;
  memset((UC*)Data,0,480);//初始化数据
  AdcStart();
  
  while(1)
  {
     _BIS_SR(LPM0_bits + GIE); //进入低功耗模式
     if(NeedSendData)
     {
       
       NeedSendData = 0;
       memcpy1((UC*)((UI)Data+12*SendPeriod),(UC*)((UI)Data+8*SendPeriod),4*SendPeriod);
       memcpy1((UC*)((UI)Data+8*SendPeriod),(UC*)((UI)Data+4*SendPeriod),4*SendPeriod);
       memcpy1((UC*)((UI)Data+4*SendPeriod),(UC*)Data,4*SendPeriod);
        
      txtoPC("Get one period data!\r\n",
             SIZEOF_STRING("Get one period data!\r\n"));
       
     }
    
  }

保存后编译一下,没有错误的话直接下载到MCU中去。实际运行一下,看看能不能正常工作。

第三步下载运行

下载之前需要注意一下仿真器是否连接正常,正常后再下载

实现一个简单的msp430软件_第16张图片
判断仿真器是否连接正常
实现一个简单的msp430软件_第17张图片
下载
实现一个简单的msp430软件_第18张图片
下载完成后

如果程序功能正常的话,按下运行键MCU会采数并且一分钟后在上位机上显示一段采数完毕的提示。
如果出现bug就要根据出错信息进行排查。

总结

当然,这只是抛砖引玉,想让大家了解一个430项目是如何完成。
重要的是要明确项目成功的定义,设立短期目标,然后在预期时间的2/3时间内完成,剩下的时间可以进行测试定稿。
单片机程序的实现方式基本相同,可能使用的寄存器定义不同,只需要看懂datasheet的相关部分,再将软件架构和逻辑想明白,基本部分就可以完成了,后期再通过测试和完善功能,接近完美的产品就产生了,当然这也是需要时间检验的。

你可能感兴趣的:(实现一个简单的msp430软件)