专注电子技术学习与研究
当前位置:单片机教程网 >> MCU设计实例 >> 浏览文章

GSM_TC35“大哥大”(1602屏显)(第二层)

作者:马梓熔   来源:马梓熔的空间   点击数:  更新时间:2014年04月10日   【字体:
从初学AT指令到用上位机成功发送指令到下位机进行固定拨打电话发中英文短信到今天2012-11-30“”大哥大“调试成功差不多花去了半个月的时光~在实验室每天花这么多时间浸淫的作品,都是血和泪,学习和积累了不少。。。。。。



















4x4keyscan.h
/***************************************************************************************************   
功能描述: 用扫描法实现矩阵键盘扫描(无源有源皆实用)
//     按键    扫描结果 |   按键   扫描结果|  按键   扫描结果 |  按键   扫描结果
//     0      0XEE      |   4     0XDE    |   8     0XBE     |   12    0X7E
//     1      0XED      |   5     0XDD    |   9     0XBD     |   13    0X7D
//     2      0XEB      |   6     0XDB    |   10    0XBB     |   14    0X7B
//     3      0XE7      |   7     0XD7    |   11    0XB7     |   15    0X77
***************************************************************************************************/
#ifndef _4x4KEYSCAN_H_
#define _4x4KEYSCAN_H_
#define uchar unsigned char
#define uint  unsigned int
#define key P2
//*****************************延时函数
void delay_1ms(uint z); 
//**************************************矩阵键盘扫描函数
KeyScan();
//***************************************矩阵键盘扫描结果处理函数
uchar KeyHandle(uchar value);
#endif  
LCD1602display.h 
#ifndef _LCD1602DISPLAY_H_
#define _LCD1602DISPLAY_H_
#define uchar unsigned char
#define uint  unsigned int
//************************LCD引脚定义
sbit LCM_RS=P1^0;
sbit LCM_RW=P1^1;
sbit LCM_E=P1^2;
//**************************延时
void delay(uint z);
//**************************初始化
void InitLCM();
//****************************读状态
uchar ReadStatusLCM();
//******************************读数据
//uchar ResdDataLCM();
//***************************写指令
void WriteCommandLCM(uchar WCLCM, Busy);
//***************************写数据
void WriteDataLCM(uchar WDLCM);
//******************************显示1个字符
void DisplayOneChar(uchar X,uchar Y,uchar DData);
//******************************显示字符串
void DisplayListChar(uchar X,uchar Y,uchar *DData);
#endif
GSM_call.h
#ifndef _GSM_CALL_H_
#define _GSM_CALL_H_
#define uchar unsigned char
#define uint  unsigned int
#define Buf_Max 40 //缓存长度40
/*
//*****************************延时函数
void delay_1ms(uint z);
*/
//************************初始化串口函数
void Serial_Init();
//************************串口发送函数
//void Send_Char(uchar ddata);
//************************串口发送字符串
void Send_String(uchar *tab);
//****************************清除缓存内容
void CLR_Buf();       
//************************串口中断函数
//void Serial()interrupt 4;
#endif 
4x4keyscan.c
#include <reg51.h>     
#include "4x4keyscan.h"
uchar z; //按键释放的标志位
uchar temp,KeyValue;          //定义扫描结果参数
//*****************************延时函数
void delay_1ms(uint z)
{
 uint x,y;
 for(x=z;x>0;x--)
  for(y=110;y>0;y--);
}
//**************************************************************************************************
//矩阵键盘扫描函数
//**************************************************************************************************
KeyScan() 
{
  uchar scode=0x00;//扫描码
  uchar rcode=0x00;//读回码
 
  key=0xf0;
  if((key&0xf0)!=0xf0)                   //判断高4位是否为全1(高4位全1代表没按键按下)
    {
      delay_1ms(10);                        //延时去抖动,一般为5ms~10ms(由于机械触点的弹性作用,按键在闭合时不会马上稳定地接通,
                                     //而在闭合瞬间伴随有一连串的抖动,键抖动会引起一次按键被误读多次)
      key=0xf0;
      if((key&0xf0)!=0xf0)               //还能检测到有键盘按下去,按行扫描
        {
  
             scode=0xfe;                   //置扫描码
          while(scode!=0xef)            //如果没有扫描完,继续扫描
             {
     
               key=scode;                //送扫描码
               if((key&0xf0)!=0xf0)      //检测到了
                 {
                    rcode=key;           //保存P2口的状态
                    rcode=rcode & 0xf0; //生成返回码高4位
                    scode=scode & 0x0f; //生成返回码低4位
                    KeyValue=scode + rcode;//返回键盘编码, 程序跳出键盘扫描函数(程序执行到return语句的时候就返回,他后面的语句都不会执行)
     
     while((key&0xf0)!=0xf0);  //等待松开按键
     z=1;       //松开按键后z置1
     return (KeyValue);     
                 }
               else
                 {
                   scode=(scode<<1)|0x01;//移位,产生下一行扫描码,顺序:0xfe>>0xfd>>0xfb>>0xf7>>0xef
                 //当扫描码为0xef时,判断条件scode!=0xe为假 ,跳出while 循环
                 }
    
             }
           return(0);  //没有检测到返回0
        }
      else             //没有键盘按下去,上一次是一个干扰
        {
         return(0);    //没有检测到返回0
        }
    }
  else  //没有键盘按下去
    {
     return(0);  //没有检测到返回0
    }
}                          
//**************************************************************************************************
//矩阵键盘扫描结果处理函数
//**************************************************************************************************
uchar KeyHandle(uchar value)                    
{
  switch(value)
  {
   case 0xee:{return(1);break;}    //对应按键S1
   case 0xde:{return(2);break;}    //对应按键S2 
   case 0xbe:{return(3);break;}    //对应按键S3 
   case 0x7e:{return(4);break;}    //对应按键S4 
   case 0xed:{return(5);break;}    //对应按键S5 
   case 0xdd:{return(6);break;}    //对应按键S6 
   case 0xbd:{return(7);break;}    //对应按键S7 
   case 0x7d:{return(8);break;}    //对应按键S8 
   case 0xeb:{return(9);break;}    //对应按键S9 
   case 0xdb:{return(10);break;}    //对应按键S10 
   case 0xbb:{return(11);break;}   //对应按键S11 
   case 0x7b:{return(12);break;}   //对应按键S12
   case 0xe7:{return(13);break;}   //对应按键S13 
   case 0xd7:{return(14);break;}   //对应按键S14 
   case 0xb7:{return(15);break;}   //对应按键S15 
   case 0x77:{return(16);break;}   //对应按键S16
   default:{return(0);break;} 
  }
}
 

LCD1602display.c
#include <reg51.h>
#include "LCD1602display.h"
//********************延时
void delay(uint z)
{
 uint i,j;
 for(i=z;i>0;i--)
  for(j=110;j>0;j--);
}
//**********************LCM初始化
void InitLCM()
{
 WriteCommandLCM(0x38,0);  //三次显示模式设置,不检测忙信号
 delay(1);
 WriteCommandLCM(0x38,0);
 delay(1);
 WriteCommandLCM(0x38,0);
 delay(1);
 WriteCommandLCM(0x38,1);  //显示模式设置:16×2显示,5×7点阵,8位数据接口
 WriteCommandLCM(0x0c,1);  //显示模式设置:显示开,无光标
 WriteCommandLCM(0x06,1);  //显示模式设置:光标右移,字符不移
 WriteCommandLCM(0x01,1);  //清屏幕指令,将以前的显示内容清除
}
//*********************读状态
uchar ReadStatusLCM()
{
 P0 = 0x80;
 LCM_RS = 0;
 LCM_RW = 1;
 LCM_E = 1;
 while (P0 & 0x80); //检测忙信号
 return(0);
}
//***********************读数据
/*uchar ResdDataLCM()
{
 LCM_RS=1;
 LCM_RW=1;
 LCM_E=1;
} */
//**********************写指令
void WriteCommandLCM(uchar WCLCM, Busy)
{
 if(Busy) ReadStatusLCM();
 P0=WCLCM;
 LCM_RS=0;
 LCM_RW=0;
 LCM_E=0;
 LCM_E=1;
}
//***********************写数据
void WriteDataLCM(uchar WDLCM)
{
 ReadStatusLCM();
 P0=WDLCM;
 LCM_RS=1;
 LCM_RW=0;
 LCM_E=0;
 LCM_E=1;
}
//*************************显示字符
void DisplayOneChar(uchar X,uchar Y,uchar DData)
{
 if(Y) X|=0X40;   //Y=1显示第二行,Y=0显示第一行
 X|=0X80;
 WriteCommandLCM(X,1); //X用来选择哪一位,1是用来忙检测
 WriteDataLCM(DData); //DData用来写数据
}
//**************************显示字符串
void DisplayListChar(uchar X,uchar Y,uchar *DData)
{
 uchar ListLength;
 ListLength=0;
 while(DData[ListLength]!='\0')
 {
  if(X<=15)
  {
   DisplayOneChar( X,Y,DData[ListLength]);
   ListLength++;
   X++;
  }
 }
}
GSM_call.c
#include <reg51.h>
#include "GSM_call.h"
uchar i=0;             //定义缓存指针 
uchar Rec_Buf[Buf_Max];  //定义缓存数组       
/*
//*****************************延时函数
void delay_1ms(uint z)
{
 uint x,y;
 for(x=z;x>0;x--)
  for(y=110;y>0;y--);
}
*/
//************************初始化串口函数
void Serial_Init()
{
 SCON=0x50;   //SM0,SM1=0,1方式1。REN=1,允许接收。
 PCON=0x00;  //比特率不加倍
 TMOD=0x20;  //定时器1的8位自动重装计数
 TH1=0xFD;  //产生波特率为9600
 TL1=0xFD;
 IE=0x90; //EA=1,ES=1开总中断和串口中断
 TR1=1;  //打开定时器1
}
//************************串口发送函数
//void Send_Char(uchar ddata)
//************************串口发送字符串
void Send_String(uchar *tab)
{
    ES = 0;                   //关串口中断,防止中断嵌套
    for (tab; *tab!='\0';tab++)
     {
         SBUF = *tab;
         while(TI!=1);     //等待发送完成
   TI = 0;           //清除发送中断标志位
  }   
 ES = 1;                   //开串口中断 
}
//****************************清除缓存内容
void CLR_Buf()
{
 uchar k;
 for(k=0;k<Buf_Max;k++)  //将缓存内容清零
  {
   Rec_Buf[k]=0;
  }  
 i=0;
}       
//************************串口中断函数
void Serial()interrupt 4
{
 ES=0;      //关串口中断,防止中断嵌套
 if(TI)      //如果是发送中断,则不做任何处理
  {
   TI=0;    //清除发送中断标志位
  }
 if(RI)      //如果是接收中断,则进行处理
  {
   RI=0;    //清除接收中断标志位
   if((SBUF<=90&&SBUF>=65)||(SBUF>=48&&SBUF<=59))  //只存储‘A-Z’大写字母和‘0-9’数字和”:;“
    {
     Rec_Buf[i] = SBUF;       //将接收到的字符串存到缓存中
     i++;                     //缓存指针向后移动
     if(i>40)                //如果缓存满,将缓存指针指向缓存的首地址
      {
       i= 0;
      }
    }
  }
 ES = 1;       //开启串口中断  

main.c 

//*******************************************************************************************
//                  mega3 大哥大(打电话、接电话)(1602回显)
//作者:马梓熔
//2012-11-30
//
//*******************************************************************************************
#include <reg51.h> 
#include "LCD1602display.h"
#include "4x4keyscan.h"
#include "GSM_call.h"
#include "stdio.h"
//********"4x4keyscan.h"
extern uchar temp,KeyValue;  
extern uchar z;
//********"GSM_call.h"
extern uchar i;             //定义缓存指针 
extern uchar Rec_Buf[Buf_Max];  //定义缓存数组
//*********main
uchar str1[]="hello  mazirong!";
uchar str2[]="calling.........";
uchar AT[]="AT\r";
uchar call[]="ATD13297961386;\r";
uchar ATA[]="ATA\r";
uchar ATH[]="ATH\r";
//**************************************拨号函数
void Phone()
{          //    "012"
 uchar m=3;       //不更改“ATD”
 while(1)                      //进入while死循环
 {
  if(i!=0)
   {
    delay(1000); //接收GSM的返回命令(这个延时很有必要)
    DisplayListChar(0,1,Rec_Buf);
  //  delay(1000);    //屏蔽
  //  WriteCommandLCM(0x01,1); //为常显    
    CLR_Buf();
   }
  KeyScan();                 //按键扫描
  temp=KeyHandle(KeyValue);  //处理扫描结果
  if(z==1)      //如果按键释放
   {       //按键标志位清0
    z=0;
    switch(temp)
     {
      case 1:
       call[m]='1';  //1 被按下
       break;
      case 2:
       call[m]='2';  //2 被按下
       break;
      case 3:
       call[m]='3';  //3 被按下
       break;
      case 4: 
       break;    //空按键
      case 5:
       call[m]='4';  //4 被按下
       break;
      case 6:
       call[m]='5';  //5 被按下
       break;
      case 7:
       call[m]='6';  //6 被按下
       break;
      case 8:
       break;    //空按键
      case 9:
       call[m]='7';  //7 被按下
       break;
      case 10:
       call[m]='8';  //8 被按下
       break;
      case 11:
       call[m]='9';  //9 被按下
       break;
      case 14:
       call[m]='0';  //0 被按下
       break;
     }
   DisplayOneChar(m-3,0,call[m]);
   m++;
   switch(temp)
    {
      case 12:     //清屏按键按下
      m=3;
      WriteCommandLCM(0x01,1);
      break;
     case 13:        //拨号按键按下
      m=3;
      Serial_Init();  
      Send_String(call);
      WriteCommandLCM(0x01,1);//清屏
      DisplayListChar(0,0,str2); //uchar str2[]="calling........."; 
      break;
     case 15:     //挂断按键按下
      m=3;
      Serial_Init();  
      Send_String(ATH);     
      WriteCommandLCM(0x01,1);//清屏   
      break;
     case 16:     //接听键按下
      m=3;
      Serial_Init();  
      Send_String(ATA);   
      WriteCommandLCM(0x01,1);//清屏               
      break;    
    }
   }
 }     
}
//********************************主函数
void main()                      

 InitLCM();     //初始化液晶
 DisplayListChar(0,0,str1); //uchar str1[]="hello  mazirong!";
 delay(1500);
 WriteCommandLCM(0x01,1); //清屏
 Serial_Init();    //串口初始化
 Send_String(AT);   //发送“AT指令”
 delay(100);        //硬件反应时间(很有必要)
 Phone();
关闭窗口