解惑,能用矩阵键盘控制lcd显示数字

用矩阵键盘控制LCD显示0—9999任意一个数,还能掉电显示。这是别人的工程,我看不太懂,板子是msp430f5529

#include  "..\inc\common.h"  //需指明相对位置 

#define  Beep_On()         P7OUT &= ~0x40  
#define  Beep_Off()        P7OUT |=  0x40  


  uint   Uout_Set;      //电压设定值 
  uint   Uout_Test;     //电压反馈值 

extern int32 Ui_Ref;


uint Adc12A_Num[80];

uint z;
uint Key_Num;//键值 

//自定义函数 
void Key_Test(void);
void Pwm_Test(void);
void Adc_Test(void); 
 


/************************************************************************
                           主函数 
*************************************************************************/
void main(void) 
{       
  System_Init();                //目标板系统 初始化      
  Led_Init();     
  //Beep_Off();    
  Lcd_Init();                   //液晶屏初始化   
  Lcd_Clr();                    //LCDLcd_Print(1,0,"  启动中......  ",16); //开机等待词条 
  //Key_Init();                   //键盘端口初始化  
  //Adc12_Init();                 //ADC12-A 初始化

  //TimeA_Init();                 //Time-A 初始化  
  //TimeB_Init();                 //Time-B 初始化
 // _EINT();                   //开启总中断     
 Delay_Ms(1000);               //延时    

  
  Lcd_Menu_Star();              //显示开始菜单
 
  
  //Adc_Test();  
  
//TA0CCR2=995;


 while(1)//------------------------------  主任务循环 
  {  
   
 
 
    /*z=P3IN&0x0f;
    if(z==0x0e)        Key_Test();
    else if(z==0x0d)   Pwm_Test();
    else if(z==0x0b)   Adc_Test();*/
    

  }//while(1) end
}//main() end  

//===============================================================================
void Key_Test(void)
{
  
   Lcd_Print(1,0,"    KEY 测试    ",16); 
   Lcd_Print(2,0,"  键值=         ",16);
   Lcd_Print(3,0,"                ",16);
  while(1)
  {
 
    Delay_Ms(50);
    if(Key_Scan()==1)
    {
      Key_Num=Key_Read()*1000; 
      Lcd_Print_Num(2,4,Key_Num,2); 
      Beep_On();
 
      while(Key_Scan()==1);     
      Beep_Off(); 
 
    }
    if((P3IN&0x0f)==0x07) 
    {
      Lcd_Menu_Star();              //显示开始菜单
      break;
    }
  }
}

void Pwm_Test(void)
{
   uint16 zz;
   
   Lcd_Print(1,0,"    PWM 测试    ",16); 
   Lcd_Print(2,0,"占空比=       %",16);
   Lcd_Print(3,0,"                ",16);
  
  while(1)
  {
      Delay_Ms(200);       
 
      zz  = TA0CCR2;  
 
      Lcd_Print_Num_Dot(2,4,zz,5);   
    if((P3IN&0x0f)==0x07) 
    {
      Lcd_Menu_Star();              //显示开始菜单
      break;
    }
    
  }
}

void Adc_Test(void)
{
  

 
   uint32 z1,U_out;
 
   uint   z2,U_set;
    uint32  zz1,zz2,zz3;
   
   Lcd_Print(1,0,"    ADC 测试    ",16); 
   Lcd_Print(2,0,"                ",16);
   Lcd_Print(3,0,"                ",16);
   
   U_set=3300; 
   
   Pid_Init(3300,0);
   
   
   z2=0;zz3=0;
   
 TA0CCR2=990;  
  while(1)
  {
     Delay_Ms(10);
     z2++;
     zz3++;
     
     if(z2>100)
     {
      z2=0;
      z1=0;
      for(z=0;z<10;z++)  z1=z1+Adc12A_Num[z*5+0];
      zz1=z1*2500/4096;
 
    
      z1=0;
      for(z=0;z<10;z++)  z1 = z1+Adc12A_Num[z*5+2];
      zz2=z1*2500/4096;     


      U_out=0;
      for(z=0;z<10;z++)  U_out=U_out+Adc12A_Num[z*5+4];
      U_out=U_out*1654/4096;     
    
 
      if((U_out<=(U_set+250))&(U_out>=(U_set-250)))            //偏差较小,进行PID调节
        {  
            TA0CCR2 = Powe_Pid(U_out,TA0CCR2);  
         // if(U_out>U_set)       TA0CCR2 =  TA0CCR2 + (U_out-U_set)/40;
         // else                  TA0CCR2 =  TA0CCR2 - (U_set-U_out)/40;
         }
      else  if((U_out<(U_set+1500))&(U_out>(U_set-1500)))   //偏差较大 比例快速调节
        {
          if(U_out>U_set)       TA0CCR2 =  TA0CCR2 + (U_out-U_set)/20;
          else                  TA0CCR2 =  TA0CCR2 - (U_set-U_out)/20;
        }
      else  // 偏差很大,直接定位
        {
          TA0CCR2 =  1000-U_set/32; //12为输入电压(单位为伏特)
        }          
     }
     
    if(zz3>40) 
    {
     Lcd_Print_Num_Dot(2,0,(uint)zz1,4);   
     Lcd_Print_Num_Dot(2,4,(uint)zz2,4); 
     Lcd_Print_Num_Dot2(3,0,(uint)U_out,4); 
     Lcd_Print_Num_Dot2(3,4,(uint)U_set,3);  
     zz3=0;
    }

    
    if((P3IN&0x0f)==0x07) 
    {
      Lcd_Menu_Star();              //显示开始菜单
      break;
    }
    else if((P3IN&0x0f)==0x0e) 
    {
      U_set=U_set+100;
    }   
    else if((P3IN&0x0f)==0x0d) 
    {
      U_set=U_set-100;
    }  

    Ui_Ref = (int32)U_set;
    while((P3IN&0x0f)<0x0f);
    
  }
}
//file end

 


#include  "..\inc\lcd.h"  //需指明相对位置

#define uint16  unsigned int
#define uint8   unsigned char

#define x1    0x80
#define x2    0x88
#define y     0x80
#define comm  0 
#define dat   1


/**************************************************************
                       LCD使用引脚情况
LCD_SCLK = P8.0
LCD_STD  = P8.1 
LCD_CS   = P8.2
***************************************************************/
#define Lcd_SClk_Set_H  P8OUT |=   BIT0
#define Lcd_SClk_Set_L  P8OUT &=  ~BIT0
#define Lcd_STD_Set_H   P8OUT |=   BIT1
#define Lcd_STD_Set_L   P8OUT &=  ~BIT1
#define Lcd_Cs_Set_H    P8OUT |=   BIT2
#define Lcd_Cs_Set_L    P8OUT &=  ~BIT2
#define Set_Lcd_Io      P8DIR |=   0x07   //P8.0,1,2配置为输出



/**************************************************************
                     LCD延时1
**************************************************************/
void Delay1_Lcd(void)   //delay time
{
    uint8 i=2;         //根据CPU时钟,调整延时时间
    while(i--);
}
/**************************************************************
                     LCD延时2
**************************************************************/
void Delay2_Lcd(uint16 ms)
{
  uint16 i,t;
  for(i=0;i<ms;i++)
    for(t=0;t<30;t++);
}
  
/**************************************************************
                      LCD写入1个字节
  参数1:选择数据、命令 
  参数2:准备要写入的数据
 
***************************************************************/
void Write_Lcd (uint8 dat_comm,uint8 content)
{
  uint8 a,i,j;
  Delay1_Lcd();
  a=content;  
  Lcd_Cs_Set_H;
  Lcd_SClk_Set_L;
  Lcd_STD_Set_H;
  for(i=0;i<5;i++)
  {
  Lcd_SClk_Set_H;
  Lcd_SClk_Set_L;
  }
  Lcd_STD_Set_L;
  Delay1_Lcd();Lcd_SClk_Set_H;
  Delay1_Lcd();Lcd_SClk_Set_L;
  if(dat_comm)  Lcd_STD_Set_H;   //data
  else   Lcd_STD_Set_L;          //command
  Delay1_Lcd();Lcd_SClk_Set_H;
  Delay1_Lcd();Lcd_SClk_Set_L; 
  Lcd_STD_Set_L;  
  Delay1_Lcd();Lcd_SClk_Set_H;
  Delay1_Lcd();Lcd_SClk_Set_L;
  for(j=0;j<2;j++)
  {
    for(i=0;i<4;i++)
    {
      if(a>0x7f) Lcd_STD_Set_H;
        else     Lcd_STD_Set_L;
      a=a<<1; 
  
  Delay1_Lcd();Lcd_SClk_Set_H;
  Delay1_Lcd();Lcd_SClk_Set_L;
    }
  Lcd_STD_Set_L;
    for(i=0;i<4;i++)
    {
  Delay1_Lcd();Lcd_SClk_Set_H;
  Delay1_Lcd();Lcd_SClk_Set_L;
    }
  }
}                                     
/**************************************************************
                     LCD 初始化
***************************************************************/
void Lcd_Init (void)
{
  Set_Lcd_Io;
  Write_Lcd (comm,0x30);  /*30H---基本指令动作*/   
  Write_Lcd (comm,0x01);  /*清屏,地址指针指向00H*/
  Delay2_Lcd  (4000);  /*复位*/
  Write_Lcd (comm,0x06);  /*光标的移动方向*/
  Write_Lcd (comm,0x0c);  /*开显示,关游标*/
}

/**************************************************************
//                LCD 刷屏函数(4X8)
//   输入参数4个:行,列,数据字串,显示字串前n个字符
//                 0  0    "1234"      4
//   返回参数   :无
***************************************************************/
void Lcd_Print(uint8 x0,uint8 y0,uint8 *chn,uint8 Char_Num)
{
  uint8 i;
  Write_Lcd (comm,0x30);
  if(x0==0)      Write_Lcd (comm,0x80+y0);
  else if(x0==1) Write_Lcd (comm,0x90+y0);
  else if(x0==2) Write_Lcd (comm,0x88+y0);
  else if(x0==3) Write_Lcd (comm,0x98+y0);
   else return; 
  for (i=0;i<Char_Num;i++) Write_Lcd (dat,chn[i]);   //第1行
}

//------------------------------------------------------
//                LCD 显示点阵函数
//======================================================
void lat_disp (uint8 data1,uint8 data2)
{
  uint8 i,j,k,x;
  x=x1;
  for(k=0;k<2;k++)
  {
    for(j=0;j<16;j++)
    {
      for(i=0;i<8;i++)
      {
        Write_Lcd (comm,0x34);
        Write_Lcd (comm,y+j*2);
        Write_Lcd (comm,x+i);
        Write_Lcd (comm,0x30);
        Write_Lcd (dat,data1);
        Write_Lcd (dat,data1);
      }
      for(i=0;i<8;i++)
      {
        Write_Lcd (comm,0x34);
        Write_Lcd (comm,y+j*2+1);
        Write_Lcd (comm,x+i);
        Write_Lcd (comm,0x30);
        Write_Lcd (dat,data2);
        Write_Lcd (dat,data2);
      }
    }
    x=x2;
  }
  Write_Lcd (comm,0x36); 
}

//------------------------------------------------------------------------------
//                      x0,y0处反白显示16xl*yl 函数
//==============================================================================
void Lcd_Disp(uint8 data1,uint8 data2,uint8 x0,uint8 y0,uint8 xl,uint8 yl)
{
  uint8 i,j;
  for(j=0;j<yl;j++)
  {
    for(i=0;i<xl;i++)
    {
      Write_Lcd (comm,0x34);
      Write_Lcd (comm,y0+j);
      Write_Lcd (comm,x0+i);
      Write_Lcd (comm,0x30);
      Write_Lcd (dat,data1);
      Write_Lcd (dat,data2);
    }
  }
  Write_Lcd (comm,0x36);
}
//------------------------------------------------------------------------------
//                          LCD 清屏函数
//==============================================================================
void Lcd_Clr (void)
{
  Write_Lcd (comm,0x30);
  Write_Lcd (comm,0x01);
  Delay2_Lcd  (4000);
}
//------------------------------------------------------------------------------
//                          系统主菜单显示函数 
//
//     创建:  周云龙    
//
//==============================================================================
void Lcd_Menu_Star(void) 
{ 
   Lcd_Print(0,0,"   2023 电赛    ",16);
   Lcd_Print(1,0,"K1  键盘测试    ",16);
   Lcd_Print(2,0,"K2 PWM测试      ",16);
   Lcd_Print(3,0,"K3 ADC测试      ",16);
 

}

/*******************************************************************************
                          
********************************************************************************/
void Lcd_Print_Num(uint8 Lcd_X,uint8 Lcd_Y,uint16 Num,uint8 Lcd_M) 
{        
    uint8 Disp_Num[6];     
    Disp_Num[0] =  Num/10000+0x30;
    Disp_Num[1] = (Num%10000)/1000+0x30;
    Disp_Num[2] = (Num%1000)/100+0x30;
    Disp_Num[3] = (Num%100)/10+0x30;
    Disp_Num[4] = Num%10+0x30;         
    Lcd_Print(Lcd_X,Lcd_Y,Disp_Num,Lcd_M);
}

/*******************************************************************************
                          
********************************************************************************/
void Lcd_Print_Num_Dot(uint8 Lcd_X,uint8 Lcd_Y,uint16 Num,uint8 Lcd_M) 
{        
    uint8 Disp_Num[6];     
    Disp_Num[0] =  Num/10000+0x30;
    Disp_Num[1] =  '.';
    Disp_Num[2] = (Num%10000)/1000+0x30;
    Disp_Num[3] = (Num%1000)/100+0x30;
    Disp_Num[4] = (Num%100)/10+0x30;
    Disp_Num[5] = Num%10+0x30;         
    Lcd_Print(Lcd_X,Lcd_Y,Disp_Num,Lcd_M+1);
}
/*******************************************************************************
                          
********************************************************************************/
void Lcd_Print_Num_Dot2(uint8 Lcd_X,uint8 Lcd_Y,uint16 Num,uint8 Lcd_M) 
{        
    uint8 Disp_Num[6];     
    Disp_Num[0] =  Num/10000+0x30;
    Disp_Num[1] = (Num%10000)/1000+0x30;
    Disp_Num[2] =  '.';    
    Disp_Num[3] = (Num%1000)/100+0x30;
    Disp_Num[4] = (Num%100)/10+0x30;
    Disp_Num[5] = Num%10+0x30;         
    Lcd_Print(Lcd_X,Lcd_Y,Disp_Num,Lcd_M+1);
   
}

  • 这篇博客: 使用超声波传感器测量距离并在LCD上显示中的 超声波距离传感器是如何工作? 部分也许能够解决你的问题, 你可以仔细阅读以下内容或跳转源博客中阅读:
  • 超声波传感器发出高频声音脉冲,然后计算声音回声反射所需的时间。传感器正面有2个开口。一个开口发射超声波(类似于微型扬声器),另一个接收它们(类似于微型麦克风)。

    空气中声速约为每秒341米(1100英尺)。超声波传感器使用该信息以及发送和接收声音脉冲之间的时间差来确定到物体的距离。它使用以下数学方程式:

    距离=时间 x 声速 / 2

    在这里插入图片描述

  • 以下回答由chatgpt基于相关博客总结生成:

    先来回答问题标题:如何使用矩阵键盘控制MSP430F5529上的LCD显示任意数字(0-9999),并实现掉电显示功能?

    为了回答这个问题,我们可以分成以下几个步骤:

    步骤1: 配置MSP430F5529的GPIO端口

    首先,我们需要配置MSP430F5529的GPIO端口来连接矩阵键盘和LCD。通过设置端口为输入或输出,我们可以读取键盘输入和控制LCD显示。具体的代码如下:

    #include <msp430.h>
    
    #define ROW_NUM 4
    #define COLUMN_NUM 4
    
    #define ROW_DIR P1DIR
    #define ROW_OUT P1OUT
    #define ROW_REN P1REN
    #define ROW_IN P1IN
    
    #define COLUMN_DIR P2DIR
    #define COLUMN_OUT P2OUT
    #define COLUMN_REN P2REN
    #define COLUMN_IN P2IN
    
    void gpio_init() {
        ROW_DIR |= (0x0F);          // 设置行为输出
        ROW_OUT &= ~(0x0F);         // 设置行为低电平
        ROW_REN |= (0x0F);          // 设置为上拉输入
        COLUMN_DIR &= ~(0xF0);      // 设置列为输入
        COLUMN_OUT |= (0xF0);       // 设置列为高电平
        COLUMN_REN |= (0xF0);       // 设置为上拉输入
        COLUMN_REN |= (0xF0);       // 设置为上拉输入
    }
    

    步骤2: 读取矩阵键盘输入

    在读取矩阵键盘输入之前,我们需要定义一个映射表,将键盘按键与对应的数字进行关联。然后我们可以通过循环扫描每一行和每一列,来判断按键是否被按下,并根据映射表的定义来确定对应的数字。具体的代码如下:

    #include <msp430.h>
    
    #define ROW_NUM 4
    #define COLUMN_NUM 4
    
    #define ROW_DIR P1DIR
    #define ROW_OUT P1OUT
    #define ROW_REN P1REN
    #define ROW_IN P1IN
    
    #define COLUMN_DIR P2DIR
    #define COLUMN_OUT P2OUT
    #define COLUMN_REN P2REN
    #define COLUMN_IN P2IN
    
    const int key_map[ROW_NUM][COLUMN_NUM] = {
      {1, 2, 3, 10},
      {4, 5, 6, 11},
      {7, 8, 9, 12},
      {15, 0, 14, 13}
    };
    
    int read_key() {
        int i, j;
    
        // 初始化键值为-1(表示无效)
        int key_val = -1;
    
        // 循环扫描每一行和每一列
        for(i = 1; i <= ROW_NUM; i++) {
            // 设置当前行为低电平
            ROW_OUT &= ~(0x0F);
            ROW_OUT |= (1 << (i - 1));
    
            // 检查列输入是否为低电平(表示按键被按下)
            for(j = 0; j < COLUMN_NUM; j++) {
                if((COLUMN_IN & (1 << (j + 4))) == 0) {
                    key_val = key_map[i - 1][j];
                    break;
                }
            }
    
            if(key_val != -1) {
                break;
            }
        }
    
        // 返回键值
        return key_val;
    }
    

    步骤3: 控制LCD显示

    在控制LCD显示之前,我们需要配置MSP430F5529的GPIO端口来连接LCD。通过设置端口为输出,我们可以控制LCD的数据和控制信号。具体的代码如下:

    #include <msp430.h>
    
    #define LCD_RS_DIR P3DIR
    #define LCD_RS_OUT P3OUT
    #define LCD_RS_BIT BIT0
    
    #define LCD_E_DIR P3DIR
    #define LCD_E_OUT P3OUT
    #define LCD_E_BIT BIT1
    
    #define LCD_DATA_DIR P3DIR
    #define LCD_DATA_OUT P3OUT
    #define LCD_DATA_BIT_0 BIT2
    #define LCD_DATA_BIT_1 BIT3
    #define LCD_DATA_BIT_2 BIT4
    #define LCD_DATA_BIT_3 BIT5
    
    void lcd_init() {
        // 配置LCD控制引脚为输出
        LCD_RS_DIR |= LCD_RS_BIT;
        LCD_E_DIR |= LCD_E_BIT;
        LCD_DATA_DIR |= (LCD_DATA_BIT_0 | LCD_DATA_BIT_1 |
                         LCD_DATA_BIT_2 | LCD_DATA_BIT_3);
    
        // 初始化LCD控制引脚
        LCD_RS_OUT &= ~LCD_RS_BIT;
        LCD_E_OUT &= ~LCD_E_BIT;
        LCD_DATA_OUT &= ~(LCD_DATA_BIT_0 | LCD_DATA_BIT_1 |
                          LCD_DATA_BIT_2 | LCD_DATA_BIT_3);
    
        // LCD初始化过程(由具体LCD型号的datasheet提供)
        // ...
    }
    

    控制LCD显示任意数字的具体过程依赖于你所使用的LCD模块的显示协议。一般来说,我们可以通过一系列的命令和数据传输,来控制LCD在指定位置显示指定的数字。以下是一个简单的示例代码,假设你的LCD显示模块使用4位数据总线和8位控制协议:

    #include <msp430.h>
    
    #define LCD_RS_DIR P3DIR
    #define LCD_RS_OUT P3OUT
    #define LCD_RS_BIT BIT0
    
    #define LCD_E_DIR P3DIR
    #define LCD_E_OUT P3OUT
    #define LCD_E_BIT BIT1
    
    #define LCD_DATA_DIR P3DIR
    #define LCD_DATA_OUT P3OUT
    #define LCD_DATA_BIT_0 BIT2
    #define LCD_DATA_BIT_1 BIT3
    #define LCD_DATA_BIT_2 BIT4
    #define LCD_DATA_BIT_3 BIT5
    
    // LCD命令定义
    #define LCD_CMD_CLEAR_DISPLAY 0x01
    #define LCD_CMD_RETURN_HOME 0x02
    #define LCD_CMD_DISPLAY_ON_OFF 0x0C
    #define LCD_CMD_FUNCTION_SET 0x28
    #define LCD_CMD_SET_DDRAM_ADDR 0x80
    
    void send_lcd_command(unsigned char command) {
        // 设置RS引脚为低电平(表示发送命令)
        LCD_RS_OUT &= ~LCD_RS_BIT;
    
        // 发送命令(根据具体连接方式和协议实现)
        // ...
    }
    
    void send_lcd_data(unsigned char data) {
        // 设置RS引脚为高电平(表示发送数据)
        LCD_RS_OUT |= LCD_RS_BIT;
    
        // 发送数据(根据具体连接方式和协议实现)
        // ...
    }
    
    void lcd_display_number(int number) {
        // 清除LCD显示
        send_lcd_command(LCD_CMD_CLEAR_DISPLAY);
    
        // 设置显示位置为第一行第一列
        send_lcd_command(LCD_CMD_SET_DDRAM_ADDR);
    
        // 将数字转化为字符串
        char number_str[5];
        snprintf(number_str, sizeof(number_str), "%d", number);
    
        // 依次发送每个字符
        for(int i = 0; i < 4; i++) {
            send_lcd_data(number_str[i]);
        }
    }
    
    int main() {
        // 初始化GPIO端口
        gpio_init();
    
        // 初始化LCD显示
        lcd_init();
    
        // 循环读取键盘输入,并在LCD上显示对应的数字
        while(1) {
            int key = read_key();
    
            // 如果按下的是数字键
            if(key >= 0 && key <= 9) {
                lcd_display_number(key);
            }
    
            // 其他操作...
        }
    
        return 0;
    }
    

    步骤4: 实现掉电显示功能

    在MSP430F5529上实现掉电显示功能需要使用非易失性存储器(如EEPROM)来保存显示的数字。当系统重新上电时,读取EEPROM中的存储数据,并在LCD上显示。具体的代码实现将涉及到MSP430F5529的EEPROM模块和相应的读写操作。以下是一个简单的示例代码,演示如何使用EEPROM保存和读取数字:

    #include <msp430.h>
    
    #define EEPROM_ADDR 0x1000       // EEPROM存储地址
    
    void eeprom_write_int(unsigned int address, int value) {
        // 设置EEPROM存储地址
        FCTL1 = FWKEY | ERASE;
        FCTL3 = FWKEY;
        *(unsigned int*)address = 0;
    
        // 写入EEPROM
        FCTL1 = FWKEY | WRT;
        *(unsigned int*)address = value;
        FCTL1 = FWKEY;
    }
    
    int eeprom_read_int(unsigned int address) {
        // 读取EEPROM
        return *(unsigned int*)address;
    }
    
    int main() {
        // ...
    
        // 保存数字到EEPROM中
        eeprom_write_int(EEPROM_ADDR, number);
    
        // ...
    
        // 从EEPROM中读取数字并在LCD上显示
        int saved_number = eeprom_read_int(EEPROM_ADDR);
        lcd_display_number(saved_number);
    
        // ...
    
        return 0;
    }
    

    以上就是如何使用矩阵键盘控制MSP430F5529上的LCD显示任意数字,并实现掉电显示功能的一般步骤和示例代码。根据具体的硬件和软件配置,你可能需要做一些调整和优化。希望这些指导和示例代码对你有所帮助!如果还有任何问题,请随时提问。