STC12C5A60S2获取GPS信息(LCD1602显示)(三)


一、简介

  计划是通过STC12C5A60S2单片机的ADC来采集霍尔传感器的电压值,并将其通过上文的2.4G Zigbee无线串口收发模块传送给树莓派。由于GPS的定位信息存在一定的误差,且项目中也不是特别需要,所以暂时不作为数据传输的对象。本文仅暂先介绍STC12C5A60S2单片机的uart串口通信。
实验图

二、前情提要

STC12C5A60S2接线说明:

STC12C5A60S2 ADC采集:

三、硬件准备

  本次实验仅仅是测试了一下Uart收发,所以并无硬件上的改动。

四、软件准备

#include "main.h"
#include "LCD1602.h"
#include "GPS.h"
#include <intrins.h>	//51基本运算(包括_nop_空函数)


//定义变量
unsigned char KEY_NUM = 0;
bit Page = 0;
unsigned char xdata Display_GPGGA_Buffer[68];
unsigned char xdata Display_GPRMC_Buffer[68];
bit Flag_OV = 0;
bit Flag_Calc_GPGGA_OK = 0;
bit Flag_Calc_GPRMC_OK = 0;


/*********************************************************************************************
*** ADC函数 ***
函数名:毫秒级CPU延时函数
调  用:DELAY_ADC_MS (?);
参  数:1~65535(参数不可为0)
返回值:无
结  果:占用CPU方式延时与参数数值相同的毫秒时间
备  注:应用于1T单片机时i<600,应用于12T单片机时i<125
/*********************************************************************************************/
void DELAY_ADC_MS (unsigned int a){
	unsigned int i;
	while( --a != 0){
		for(i = 0; i < 600; i++);
	}
}
/*********************************************************************************************
函数名:10位A/D转换初始化函数
调  用:Read_init (?);
参  数:输入的端口(0000 0XXX 其中XXX是设置输入端口号,可用十进制0~7表示,0表示P1.0,7表示P1.7)
返回值:无
结  果:开启ADC功能并设置ADC的输入端口
备  注:使用ADC功能时需要将对应的IO接口设置为高阻输入方式(例如:P1M1 = 0x01;)
/**********************************************************************************************/
void Read_init (unsigned char CHA){
	unsigned char AD_FIN=0; //存储A/D转换标志
    CHA &= 0x07;            //选择ADC的8个接口中的一个(0000 0111 清0高5位)
    ADC_CONTR = 0x40;		//ADC转换的速度(0XX0 0000 其中XX控制速度,请根据数据手册设置)
    _nop_();
    ADC_CONTR |= CHA;       //选择A/D当前通道
    _nop_();
    ADC_CONTR |= 0x80;      //启动A/D电源
    DELAY_ADC_MS(1);            //使输入电压达到稳定(1ms即可)
}
/**********************************************************************************************/
/*********************************************************************************************
函数名:10位A/D转换函数
调  用:? = ADC_Read();
参  数:无
返回值:10位ADC数据高(从0到1023(十进制))
结  果:读出指定ADC接口的A/D转换值,并返回数值
备  注:适用于STC12C5A60S2系列单片机(必须使用STC12C5A60S2.h头文件)
/**********************************************************************************************/
unsigned int ADC_Read (void){
	unsigned char AD_FIN=0; //存储A/D转换标志
    ADC_CONTR |= 0x08;      //启动A/D转换(0000 1000 令ADCS = 1)
    _nop_();
    _nop_();
    _nop_();
    _nop_();
    while (AD_FIN ==0){     //等待A/D转换结束
        AD_FIN = (ADC_CONTR & 0x10); //0001 0000测试A/D转换结束否
    }
    ADC_CONTR &= 0xE7;      //1111 0111 清ADC_FLAG位, 关闭A/D转换, 
return (ADC_RES*4+ADC_RESL);//返回A/D转换结果(10位ADC数据高8位在ADC_RES中,低2位在ADC_RESL中)
}




//****************************************************
//主函数
//****************************************************
void main()
{
	unsigned int m;
	//unsigned long str[5];
	unsigned char i = 0;
 
	Init_LCD1602();
	LCD1602_write_com(0x80);						//指针设置
	//LCD1602_write_word("come to use!");
	LCD1602_write_word("xxWelcome to use!");
	Delay_ms(1000);


	Uart_Init();

	P1M1 = 0x01;//与2052正好是相反的设置                           
	Read_init (0);
  m = ADC_Read();
	//str[0]=m/1000+48; //取千位      48 = 0x30
	//str[1]=(m%1000)/100+48; //取百位
	//str[2]=(m%100)/10+48; //取十位
	//str[3]=m%10+48;

	Delay_ms(1000);
	LCD1602_write_com(0x80+0x40);			//设置指针
	LCD1602_write_word("AD:");
	LCD1602_write_data(m/1000+0x30);
	LCD1602_write_data((m%1000)/100+0x30);
	LCD1602_write_data((m%100)/10+0x30);
	LCD1602_write_data(m%10+0x30);



	while(1)
	{
		Scan_Key();
		m = ADC_Read();
		//str[0]=m/1000+48; //取千位
		//str[1]=(m%1000)/100+48; //取百位
		//str[2]=(m%100)/10+48; //取十位
		//str[3]=m%10+48;
		if(Flag_GPS_OK == 1 && RX_Buffer[4] == 'G' && RX_Buffer[6] == ',' && RX_Buffer[13] == '.')			//确定是否收到"GPGGA"这一帧数据
		{
			for( i = 0; i < 68 ; i++)
			{
				Display_GPGGA_Buffer[i] = RX_Buffer[i];	
			}
			Hour = (Display_GPGGA_Buffer[7]-0x30)*10+(Display_GPGGA_Buffer[8]-0x30)+8;			//UTC时间转换到北京时间		UTC+8
																								//0x30为ASCII转换为数字
			if( Hour >= 24)				//溢出
			{
				Hour %= 24;				//获取当前Hour
				Flag_OV = 1;			//日期进位
			}
			else
			{
				Flag_OV = 0;
			}

			Min_High = Display_GPGGA_Buffer[9];
			Min_Low = Display_GPGGA_Buffer[10];
	
			Sec_High = Display_GPGGA_Buffer[11];
			Sec_Low = Display_GPGGA_Buffer[12];

			Flag_Calc_GPGGA_OK = 1;
		}

		if(Page == 0 && Flag_Calc_GPGGA_OK == 1)
		{
			LED1 = ~LED1;
			Flag_Calc_GPGGA_OK = 0;
			LCD1602_write_com(0x80);			//设置指针
			LCD1602_write_data(Hour/10+0x30);
			LCD1602_write_data(Hour%10+0x30);

			LCD1602_write_data(':');

			LCD1602_write_data(Min_High);
			LCD1602_write_data(Min_Low);

			LCD1602_write_data(':');
	
			LCD1602_write_data(Sec_High);
			LCD1602_write_data(Sec_Low);

			LCD1602_write_word("  ");
			
			LCD1602_write_data(Display_GPGGA_Buffer[54]);	
			LCD1602_write_data(Display_GPGGA_Buffer[55]);	
			LCD1602_write_data(Display_GPGGA_Buffer[56]);	
			LCD1602_write_data(Display_GPGGA_Buffer[57]);
			LCD1602_write_word("m");
	
			LCD1602_write_com(0x80+0x40);			//设置指针
			
			LCD1602_write_data(Display_GPGGA_Buffer[28]);			//N 或者 S

			LCD1602_write_data(Display_GPGGA_Buffer[17]);			//纬度
			LCD1602_write_data(Display_GPGGA_Buffer[18]);			//纬度
			LCD1602_write_data(0xdf);								//度
			LCD1602_write_data(Display_GPGGA_Buffer[19]);			//纬度
			LCD1602_write_data(Display_GPGGA_Buffer[20]);			//纬度
			LCD1602_write_word("'");								//秒
			
			LCD1602_write_data(Display_GPGGA_Buffer[42]);			//E 或者 W

			LCD1602_write_data(Display_GPGGA_Buffer[30]);			//经度
			LCD1602_write_data(Display_GPGGA_Buffer[31]);	
			LCD1602_write_data(Display_GPGGA_Buffer[32]);	
			LCD1602_write_data(0xdf);		             //°						
			LCD1602_write_data(Display_GPGGA_Buffer[33]);			
			LCD1602_write_data(Display_GPGGA_Buffer[34]);		
			LCD1602_write_word("'");

						
		}
		
		if(Flag_GPS_OK == 1 && RX_Buffer[4] == 'M' && RX_Buffer[52] == ',' && RX_Buffer[59] == ',')			//确定是否收到"GPRMC"这一帧数据
		{
			for( i = 0; i < 68 ; i++)
			{
				Display_GPRMC_Buffer[i] = RX_Buffer[i];	
			}

			Year_High = Display_GPRMC_Buffer[57];
			Year_Low = Display_GPRMC_Buffer[58];

			Month_High = Display_GPRMC_Buffer[55];
			Month_Low = Display_GPRMC_Buffer[56];

			Day_High = Display_GPRMC_Buffer[53];
			Day_Low = Display_GPRMC_Buffer[54];


			if(Flag_OV == 1)			//有进位
			{
				UTCDate2LocalDate();			//UTC日期转换为北京时间		
			}

			Flag_Calc_GPRMC_OK = 1;

			UartPrintf("INDEX:");	
			UartPrintASCII('"');	
			UartPrintf("1");
			UartPrintASCII('"');
			UartPrintf("\r\n");
			UartPrintf("AD:");
			UartPrintASCII('"');	
			UartPrintASCII(m/1000+0x30);	
			UartPrintASCII((m%1000)/100+0x30);	
			UartPrintASCII((m%100)/10+0x30);	
			UartPrintASCII(m%10+0x30);	
			UartPrintASCII('"');
			UartPrintf("\r\n");
			//Delay_ms(10000);
		}

		if(Page == 1 && Flag_Calc_GPRMC_OK == 1)
		{
			LED1 = ~LED1;
			Flag_Calc_GPRMC_OK = 0;
			LCD1602_write_com(0x80);			//设置指针
			LCD1602_write_word("20");
			LCD1602_write_data(Year_High);
			LCD1602_write_data(Year_Low);
			LCD1602_write_data('-');
	
			LCD1602_write_data(Month_High);
			LCD1602_write_data(Month_Low);
			LCD1602_write_data('-');
	
			LCD1602_write_data(Day_High);
			LCD1602_write_data(Day_Low);

			LCD1602_write_data(' ');
			LCD1602_write_data(m/1000+0x30);
			LCD1602_write_data((m%1000)/100+0x30);
			LCD1602_write_data((m%100)/10+0x30);
			LCD1602_write_data(m%10+0x30);

			
			
			LCD1602_write_com(0x80+0x40);			//设置指针
			LCD1602_write_word("Speed:");				//显示内容

			LCD1602_write_data(Display_GPRMC_Buffer[46]);		
			LCD1602_write_data(Display_GPRMC_Buffer[47]);		
			LCD1602_write_data(Display_GPRMC_Buffer[48]);			
			LCD1602_write_data(Display_GPRMC_Buffer[49]);	
			LCD1602_write_data(Display_GPRMC_Buffer[50]);
			
			LCD1602_write_word("m/s");	
			
		}		

		// 在此处发送数据会导致Page换页变得卡顿
			/*UartPrintf("INDEX:");	
			UartPrintASCII('"');	
			UartPrintf("1");
			UartPrintASCII('"');
			UartPrintf("\r\n");
			UartPrintf("AD:");
			UartPrintASCII('"');	
			UartPrintASCII(m/1000+0x30);	
			UartPrintASCII((m%1000)/100+0x30);	
			UartPrintASCII((m%100)/10+0x30);	
			UartPrintASCII(m%10+0x30);	
			UartPrintASCII('"');
			UartPrintf("\r\n");
			Delay_ms(10000);*/
	}
}
//****************************************************
//UTC日期与当地日期转换
//****************************************************
void UTCDate2LocalDate(void)
{
	Day = (Day_High - 0x30) * 10 + (Day_Low-0x30) + 1;		//日  加一
	Month = (Month_High - 0x30) * 10 + (Month_Low - 0x30);
	Year = 2000 + (Year_High - 0x30) * 10 + (Year_Low - 0x30);
	
	MaxDay = GetMaxDay(Month,Year);				//获取当月 天数 最大值
	if(Day > MaxDay)		//溢出
	{
		Day = 1;
		Month += 1;
		if(Month > 12)
		{
			Year+=1;
		}
	}

	Day_High = Day/10 + 0x30;				//转换日期值为ASCII
	Day_Low = Day%10 + 0x30;

	Month_High = Month/10 + 0x30;			//转换月份值为ASCII
	Month_Low = Month%10 + 0x30;

	Year_High = Year%100/10 + 0x30;			//转换年份值为ASCII
	Year_Low = Year%10 + 0x30;			
}

//****************************************************
//获取当月日期最大值
//****************************************************
unsigned char GetMaxDay(unsigned char Month_Value,unsigned int Year_Value)
{
	unsigned char iDays;
	switch(Month_Value)
	{
		case 1:
		case 3:
		case 5:
		case 7:
		case 8:
		case 10:
		case 12:
			{
				iDays = 31;
			}
			break;
		case 2:
			{
				//2月份比较特殊,需要根据是不是闰年来判断当月是28天还29天
				iDays = IsLeapYear(Year_Value)?29:28;
			}
			break;
		case 4:
		case 6:
		case 9:
		case 11:
			{
				iDays = 30;
			}
			break;
		default : break;
	}
	return(iDays);						
}

//****************************************************
//闰年检测
//****************************************************
bit IsLeapYear(unsigned int uiYear)
{
	return (((uiYear%4)==0)&&((uiYear%100)!=0))||((uiYear%400)==0);
}


//****************************************************
//按键扫描程序
//****************************************************
void Scan_Key()
{
	if( KEY4 == 0 )	 					//按键1扫描
	{
		Delay_ms(10);					//延时去抖
		if( KEY4 == 0 )
		{
			while(KEY4 == 0);			//等待松手
			KEY_NUM = 3;
			Page = ~Page;
			LCD1602_write_com(0X01);	//清屏
		}
	}
}
//****************************************************
//MS延时函数(12M晶振下测试)
//****************************************************
void Delay_ms(unsigned int n)
{
	unsigned int  i,j;
	for(i=0;i<n;i++)
		for(j=0;j<123;j++);
}

  发送指定索引和所采集到的ADC值到PC。
在这里插入图片描述

五、参考例程

#include <reg51.h>
 
typedef   unsigned char  uint8;
typedef   unsigned int   uint16;
 
uint8 Buf[]="hello world!\n";
 
void delay(uint16 n)
{
	while (n--);
}
 
/*波特率为9600*/
void UART_init(void)
{
    SCON = 0x50;        //串口方式1
 
    TMOD = 0x20;        // 定时器使用方式2自动重载
    TH1 = 0xFD;    //9600波特率对应的预设数,定时器方式2下,TH1=TL1
    TL1 = 0xFD;
 
    TR1 = 1;//开启定时器,开始产生波特率
}
 
/*发送一个字符*/
void UART_send_byte(uint8 dat)
{
	SBUF = dat;       //把数据放到SBUF中
	while (TI == 0);//未发送完毕就等待
	TI = 0;    //发送完毕后,要把TI重新置0
}
 
/*发送一个字符串*/
void UART_send_string(uint8 *buf)
{
	while (*buf != '\0')
	{
		UART_send_byte(*buf++);
	}
}
 
void main()
{
	UART_init();
	
	while (1)
	{
		UART_send_string(Buf);
		delay(20000);
	}
 
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

TomLazy

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值