TI中文支持网
TI专业的中文技术问题搜集分享网站

MSP430F149,程序运行,LCD上没有任何数据

正在学习做一个基于MSP430的交流电采集系统,用示波器检测过了输入口的波形,是没有问题的。

问题是LCD只是亮的,上面没有任何数据,怀疑是数据没有传输到LCD上面去,想知道是怎么事,我不知道显示程序哪里出了问题?

MSP430采用的最小系统板,输入信号与连接LCD的部分电路如图所示:

程序如下:

//软件设计介绍:基于MSP430的单相交流电能质量采集模块程序
//***************************************************
//功能介绍:对220V交流电能质量的采集并显示
//对P6.0口电压进行采集 液晶显示(输入的是脉冲波形(去除掉正弦波形的负半周))
//对P6.1口电流进行采集 液晶显示(同上)
//对P2.3口频率进行采集 液晶显示(输入的方波)
/*
LCD16x2
预演效果如下
****************
V:220.0V I:400uA
P:50.00Hz
*/
//****************************************************
#include  <msp430x14x.h>
#include  "cry1602.h"
//#include  "cry1602.c"
//有一个报错:目前的解决方案是注释掉上面一行的语句,并且把1602.C里面的int,char定义放到.h里面去
#define   Num_of_Results   32   

uchar shuzi[] = {"0123456789."};//定义数字
uchar tishi1[] = {"V:"};//定义提示电压信息uchar tishi2[] = {"I:"};//定义提示电流信息
uchar tishi3[] = {"P:"};//定义提示频率信息
uchar tishi4[] = {"uA"};//定义提示电流单位
uchar tishi5[] = {"Hz"};//定义提示频率信息

uint start,end;
uint width; //==用于存放脉宽==
uint period; //==用于存放周期==
uint frequency; //==用于存放频率==
uint fy[4]; //==用于存放频率显示数据==
void process(void); //==函数声明==
void InitSys();    //==初始化时钟==

static uint A0results[Num_of_Results];    //保存ADC转换结果的数组  
static uint A1results[Num_of_Results];    //保存ADC转换结果的数组
void Trans_val(uint Hex_Val);
void Trans_val1(uint Hex_Val);

/**********************************************************/
void main(void)
{
  WDTCTL = WDTPW+WDTHOLD;                   //关闭看门狗  LcdReset();                               //复位1602液晶
  DispNChar(0,0,2,tishi1);                  //显示电压提示信息  //分配电压信息的坐标值(第1个位置开始,放在LCD的第1行)
  DispNChar(9,0,2,tishi2);                  //显示电流提示信息
  DispNChar(0,1,2,tishi3);                  //显示频率提示信息
  Disp1Char(7,0,'V');                      //显示电压单位V
  DispNChar(14,0,2,tishi4);                   //显示电流单位uA
  DispNChar(7,1,2,tishi5);                      //显示频率单位Hz
 //ADC的初始化
  P6SEL |= BIT0;                            //使能ADC通道A0,即P6.0口(采集电压)0x01
  P6SEL |= BIT1;                            //使能ADC通道A1,即P6.1口(采集电流) 0x02  ADC12CTL0 = ADC12ON+SHT0_8+MSC;           //打开ADC,设置采样时间 SHT0_8是64分频
  //上面的配置没有打开内部的参考电压
  //ADC12MCTLx用来选择通道和参考电压,这里面没有对此寄存器进行配置为默认的值
  //默认值是参考电压选择AVCC(3.3V),通道是A0,所以测量范围是0~3.3V
  //选择通道与参考电压的被省略: ADC12MCTL0=ADC12INCH_0+ADC12SREF_1;
  ADC12CTL1 = CSTARTADD_0+SHP+CONSEQ_3;                 //使用采样定时器,序列通道多次重复采集
  //寄存器配置采样保持触发源选择时ADC12SC,采样信号使用采样时序电路产生的信号
  ADC12IE = BIT0;                           //使能ADC中断 P6.0
  ADC12IE = BIT1;                           //使能ADC中断 P6.1
  ADC12CTL0 |= ENC;                         //使能转换
  ADC12CTL0 |= ADC12SC;                     //开始转换
  //定时器的初始化
  InitSys(); //==初始化时钟,SMCLK,MCLK均为8M==
   P2DIR&=~BIT3;
  P2SEL = BIT3; //==设置P1.2端口为功能模块使用,即:做捕获源==
  TACTL = TASSEL_2+ID_3+TACLR+TAIE+MC1;//==定时器A时钟信号选择SMCLK,8分频,同时设置定时器A计数模式为连续增计模式==   
   CCTL1 = CM_1+SCS+CAP+CCIE; //==输入上升沿捕获,CCI0A为捕获信号源==

  _EINT();                                  //使能中断,(开启全局中断)
  LPM0;                                     //低功耗模式
}

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

//ADC中断服务函数
#pragma vector=ADC_VECTOR                   
__interrupt void ADC12ISR (void)
{
  static uint index = 0;
  A0results[index++] = ADC12MEM0;// 将转换出来的结果存入数组
  A1results[index++] = ADC12MEM1;// 将转换出来的结果存入数组
  if(index == Num_of_Results)//如果数组存满           
  {
        uchar i;
        unsigned long sum0 = 0;
        unsigned long sum1 = 0;
        index = 0;//再重新开始存放数组(会导致覆盖原有的数据)
        for(i = 0; i < Num_of_Results; i++)//计算数组的和
        {
            sum0 += A0results[i];
            sum1 += A1results[i];
        }
        sum0 >>= 5;                            //除以32,得到平均值,因为前面定义了一个32,即采集32次
        sum1 >>= 5;
        sum0=(sum0<<7)+(sum0<<5)+(sum0<<4);
        //采集时电压在前端的处理电路中被放小了多少,
        //这里就放大回去,分析得出应该为176倍(变回220V)
        sum1=(sum1<<10)+(sum1<<6)+(sum1<<5)+(sum1<<3)+(sum1<<2);
        //放大回去,分析得出应该为1132倍        //(这里求电流,1K的采样电阻要/1000,但是单位A变为uA要*10^6,所以是*1000)
        Trans_val(sum0);
        Trans_val1(sum1);
  }
}

/**********************************************************/
/********频率采集处理模块**********/
//时钟初始化函数
void InitSys(){   unsigned int i; //— 使用XT2振荡器,8MHz的那个 —   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,8M==  
}

//中断处理函数
#pragma vector=TIMERA1_VECTOR //==定时器A中断处理==
__interrupt void timer_a(void)
{
  switch(TAIV) //==向量查询==
  { case 2: //==捕获中断==
       if(CCTL1&CM0) //==捕获到上升沿==
         {
            CCTL1=(CCTL1&(~CM0))|CM1; //==更变设置为下降沿触发==
           start=TAR; //==记录初始时间==           
         }
    
       else if (CCTL1&CM1) //==捕获到下降沿==
        {
            CCTL1=(CCTL1&(~CM1))|CM0; //==更变设置为上升沿触发==
           end=TAR; //==用start,end,overflow计算脉冲宽度==
           
        }
        break;
                    
    default:
       break;
  }
}
  //数据处理函数
void process(void)
{
    while(end<start);
    //while(end<start)的话就让其一直等待下去,直到end>start
    uchar i;
    width = end-start; //==实际脉冲宽度的计算==
    period = 2* width;
    frequency=10000/period; //这里放大的目的是为了后面便于显示
       
    fy[0]=frequency/10000;
    fy[1]=(frequency-10000*fy[0])/1000;
    fy[3]=(frequency-10000*fy[0]-1000*fy[1])/100;
    fy[4]=(frequency-10000*fy[0]-1000*fy[1]-100*fy[3])/10;
    fy[2]=shuzi[10];
    for(i = 0;i < 5;i++)
    Disp1Char((2 + i),1,shuzi[fy[i]]); //第3个开始显示5位 ,例如 50.00,然后在第8位加上单位Hz)
}

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

//将16进制的ADC转换数据变为10进制的模拟电压,电流数据并显示到LCD上面
//电压转换部分
void Trans_val(uint Hex_Val)
{
    unsigned long caltmp;
    uint Curr_Volt;
    uchar t1,i;
    uchar ptr[5];  
    caltmp = Hex_Val;
    caltmp = (caltmp << 5) + Hex_Val;           //caltmp = Hex_Val * 33 扩大10倍便于计算
    caltmp = (caltmp << 3) + (caltmp << 1);     //caltmp = caltmp * 10  扩大10倍便于计算
    Curr_Volt = (caltmp >> 12);                   //Curr_Volt = caltmp / 2^n  
    //由于这里是V为单位,要转化为
    //参考电压为3.3V,所以计算公式应该为Hex_Val*3.3/2^n
    //在程序计算的过程中位移运算是最有效率的
    //实际电压值是3.3*(ad采样值)/1024(v)
    ptr[0] = Curr_Volt / 10000;//百位上面的数字(Hex到Dec的变换)因为放大了,所以要除以100*100
    ptr[1] = (Curr_Volt % 10000)/1000; //十位上面的数字    ptr[2] = (Curr_Volt % 1000)/100; //个位上面的数字
    t1 = Curr_Volt – (ptr[0] * 10000)-(ptr[1] * 1000)-(ptr[2] * 100);
    ptr[4] = t1 / 10;//相当于小数点后第一位
    ptr[3] = shuzi[10];//数字表中第10位对应符号"."
    //在液晶上显示变换后的结果
    for(i = 0;i < 5;i++)
    Disp1Char((2 + i),0,shuzi[ptr[i]]);  //(第3个开始显示5位 ,例如 220.0,然后在第8位加上单位V)
}

//电流转换部分
void Trans_val1(uint Hex_Val)
{
    unsigned long caltmp;
    uint Curr_I;
    uchar i;
    uchar ptr[3];  
    caltmp = Hex_Val;
    caltmp = (caltmp << 5) + Hex_Val;           //caltmp = Hex_Val * 33 扩大10倍便于计算
    caltmp = (caltmp << 3) + (caltmp << 1);     //caltmp = caltmp * 10  扩大10倍便于计算
    Curr_I = caltmp >> 12;                   //Curr_Volt = caltmp / 2^n
    //参考电压为3.3V,所以计算公式应该为Hex_Val*3.3/2^n
    //在程序计算的过程中位移运算是最有效率的
    //实际电压值是3.3*(ad采样值)/1024(v)
    ptr[0] = Curr_I / 10000;//百位上面的数字(Hex到Dec的变换)
    ptr[1] = (Curr_I % 10000)/1000; //十位上面的数字    ptr[2] = (Curr_I % 1000)/100; //个位上面的数字
    //在液晶上显示变换后的结果
    for(i = 0;i < 3;i++)
    Disp1Char((11 + i),0,shuzi[ptr[i]]); //(第12个开始显示3位 ,例如 400,然后在第15位加上单位uA)
}

下面是cry1602.C的程序,直接用的网上的

#include <msp430x14x.h>
#include "cry1602.h"

/**************宏定义***************/
#define DataDir     P4DIR
#define DataPort    P4OUT
#define Busy    0x80
#define CtrlDir     P3DIR
#define CLR_RS P3OUT&=~BIT0;    //RS = P3.0
#define SET_RS P3OUT|=BIT0;
#define CLR_RW P3OUT&=~BIT1;//RW = P3.1
#define SET_RW P3OUT|=BIT1;
#define CLR_EN P3OUT&=~BIT2;//EN = P3.2
#define SET_EN P3OUT|=BIT2;
/***********************************************
函数名称:DispStr
功    能:让液晶从某个位置起连续显示一个字符串
参    数:x–位置的列坐标
          y–位置的行坐标
          ptr–指向字符串存放位置的指针
返回值  :无
***********************************************/
void DispStr(uchar x,uchar y,uchar *ptr){
 
    uchar *temp;
    uchar i,n = 0;
     
    temp = ptr;
    while(*ptr++ != '\0')   n++;    //计算字符串有效字符的个数
     
    for (i=0;i<n;i++)
    {
 
        Disp1Char(x++,y,temp[i]);
        if (x == 0x0f)
        {
 
           x  = 0;           y ^= 1;
         
}
     
}
 
}
/*******************************************
函数名称:DispNchar
功    能:让液晶从某个位置起连续显示N个字符
参    数:x–位置的列坐标
          y–位置的行坐标
          n–字符个数
          ptr–指向字符存放位置的指针
返回值  :无
********************************************/
void DispNChar(uchar x,uchar y, uchar n,uchar *ptr){
 
    uchar i;
     
    for (i=0;i<n;i++)
    {
 
        Disp1Char(x++,y,ptr[i]);
        if (x == 0x0f)
        {
 
           x = 0;        y ^= 1;
         
}
     
}
 
}
/*******************************************
函数名称:LocateXY
功    能:向液晶输入显示字符位置的坐标信息
参    数:x–位置的列坐标
          y–位置的行坐标
返回值  :无
********************************************/
void LocateXY(uchar x,uchar y){
 
    uchar temp;
 
    temp = x&0x0f;
    y &= 0x01;
    if(y)   temp |= 0x40;  //如果在第2行
    temp |= 0x80;
 
    LcdWriteCommand(temp,1);
 
}
/*******************************************
函数名称:Disp1Char
功    能:在某个位置显示一个字符
参    数:x–位置的列坐标
          y–位置的行坐标
          data–显示的字符数据
返回值  :无
********************************************/
void Disp1Char(uchar x,uchar y,uchar data){
 
    LocateXY( x, y );
    LcdWriteData( data );
 
}
/*******************************************
函数名称:LcdReset
功    能:对1602液晶模块进行复位操作
参    数:无
返回值  :无
********************************************/
void LcdReset(void){
 
    CtrlDir |= 0x07;                 //控制线端口设为输出状态    DataDir  = 0xFF;                 //数据端口设为输出状态
   
    LcdWriteCommand(0x38, 0);    //规定的复位操作
    Delay5ms();
    LcdWriteCommand(0x38, 0);
    Delay5ms();
    LcdWriteCommand(0x38, 0);
    Delay5ms();
 
    LcdWriteCommand(0x38, 1);//显示模式设置
    LcdWriteCommand(0x08, 1);//显示关闭
    LcdWriteCommand(0x01, 1);    //显示清屏
    LcdWriteCommand(0x06, 1);//写字符时整体不移动
    LcdWriteCommand(0x0c, 1);//显示开,不开游标,不闪烁
 
}
/*******************************************
函数名称:LcdWriteCommand
功    能:向液晶模块写入命令
参    数:cmd–命令,
          chk–是否判忙的标志,1:判忙,0:不判
返回值  :无
********************************************/
void LcdWriteCommand(uchar cmd,uchar chk){
 
 
    if (chk) WaitForEnable();   // 检测忙信号?
     
    CLR_RS;
    CLR_RW;    _NOP();
 
    DataPort = cmd;             //将命令字写入数据端口    _NOP();
     
    SET_EN;                     //产生使能脉冲信号
    _NOP();
    _NOP();
    CLR_EN;
 
}
 
/*******************************************
函数名称:LcdWriteData
功    能:向液晶显示的当前地址写入显示数据
参    数:data–显示字符数据
返回值  :无
********************************************/
void LcdWriteData( uchar data ){
 
    WaitForEnable();        //等待液晶不忙
 
    SET_RS;
    CLR_RW;    _NOP();
 
    DataPort = data;        //将显示数据写入数据端口
    _NOP();
 
    SET_EN;                 //产生使能脉冲信号
    _NOP();    _NOP();    CLR_EN;
 
}
/*******************************************
函数名称:WaitForEnable
功    能:等待1602液晶完成内部操作
参    数:无
返回值  :无
********************************************/
void WaitForEnable(void){
 
    P4DIR &= 0x00;  //将P4口切换为输入状态
 
    CLR_RS;
    SET_RW;
    _NOP();
    SET_EN;    _NOP();
    _NOP();
 
    while((P4IN & Busy)!=0);  //检测忙标志
 
    CLR_EN;
 
    P4DIR |= 0xFF;  //将P4口切换为输出状态
 
}
                        
/*******************************************
函数名称:Delay5ms
功    能:延时约5ms
参    数:无
返回值  :无
********************************************/
void Delay5ms(void)
{
     uint i=40000;
    while (i != 0)
    {
 
        i–;
     
}
 
}

//CRY1602.h的声明

void DispNChar(unsigned char x,unsigned char y, unsigned char n,unsigned char *ptr);
void LocateXY(unsigned char x,unsigned char y);
void Disp1Char(unsigned char x,unsigned char y,unsigned char data);
void LcdReset(void);
void LcdWriteCommand(unsigned char cmd,unsigned char chk);
void LcdWriteData( unsigned char data );
void WaitForEnable(void);
void Delay5ms(void);

typedef unsigned char uchar;
typedef unsigned int  uint;

灰小子:

建议先单独调试msp430f149驱动led屏的部分,驱动没问题了再和采样部分联合调试

XueSong Ye:

回复 灰小子:

好的,我先试试。谢谢您的回复!

XueSong Ye:

回复 XueSong Ye:

直接Debug的时候,到看门狗的这一步的时候就出现了这几个警告:

Wed May 31, 2017 17:52:36: Illegal register  P2IE.P6  in interrupt description: PORT2_VECTOR  0x02  2  P2IE.P6  P2IFG.P6 Wed May 31, 2017 17:52:36: Illegal register  P2IE.P7  in interrupt description: PORT2_VECTOR  0x02  2  P2IE.P7  P2IFG.P7 Wed May 31, 2017 17:52:36: Illegal register  ADC12IE  in interrupt description: ADC12_VECTOR  0x0E  2  ADC12IE  ADC12IFG

这些非法寄存器描述是怎么回事,没看懂,求指点。

灰小子:

回复 XueSong Ye:

奇怪的问题。这是否单独调试lcd显示测程序时遇到的问题?

lcd显示程序应该用不到io中断吧?

XueSong Ye:

回复 灰小子:

不是。程序整体跑起来的时候出的这个警告。另外,我的LCD部分的程序是直接用的Cry1602.C里面的函数。不知道该如何调试QAQ

HG:

回复 XueSong Ye:

1602的例程应该很多啊。LCD亮应该只能说明上电没问题,调试思路是:

把中断,ADC,低功耗等等全部去掉,留下单纯的LCD程序。然后用示波器捕捉DATA,CS的信号看是不是跟发出来的一样。

赞(0)
未经允许不得转载:TI中文支持网 » MSP430F149,程序运行,LCD上没有任何数据
分享到: 更多 (0)