相信接触过STC15系列单片机的小伙伴们,应该会对其编程风格比较熟悉,没错,STC15系列单片机可以采用库函数编程,官方提供了标准的函数库,我们只需要利用好库函数,便可大大简化配置流程,从而提高编程效率。由于笔者这里的教程不是关于51单片机的基础教程,所以此处省去了新建工程以及如何添加库文件等操作。
首先,我们要养成良好的习惯,在使用任何一款板子的时候,先建一个配置板载资源的文件,当然要是板子比较复杂的话,可以分模块配置多个,由于笔者使用的板子比较简单,所以就只添加了为“bsp_gpio.h”和“bsp_gpio.c”的文件,顾名思义,就是一些输入输出的配置而已了。
#ifndef __BSP_GPIO_H__
#define __BSP_GPIO_H__
#include "GPIO.h"
/****************** ADC GPIO ******************/
//ADC0 - ADC1
#define ADC0_GPIO_PIN GPIO_Pin_1
#define ADC0_GPIO GPIO_P1
#define ADC1_GPIO_PIN GPIO_Pin_0
#define ADC1_GPIO GPIO_P1
/****************** 输出GPIO ******************/
//Y00 - Y05
#define Y00 P37
#define Y00_GPIO_PIN GPIO_Pin_7
#define Y00_GPIO GPIO_P3
#define Y01 P36
#define Y01_GPIO_PIN GPIO_Pin_6
#define Y01_GPIO GPIO_P3
#define Y02 P35
#define Y02_GPIO_PIN GPIO_Pin_5
#define Y02_GPIO GPIO_P3
#define Y03 P34
#define Y03_GPIO_PIN GPIO_Pin_4
#define Y03_GPIO GPIO_P3
#define Y04 P33
#define Y04_GPIO_PIN GPIO_Pin_3
#define Y04_GPIO GPIO_P3
#define Y05 P32
#define Y05_GPIO_PIN GPIO_Pin_2
#define Y05_GPIO GPIO_P3
//X00 - X07
#define X00 P12
#define X00_GPIO_PIN GPIO_Pin_2
#define X00_GPIO GPIO_P1
#define X01 P13
#define X01_GPIO_PIN GPIO_Pin_3
#define X01_GPIO GPIO_P1
#define X02 P14
#define X02_GPIO_PIN GPIO_Pin_4
#define X02_GPIO GPIO_P1
#define X03 P15
#define X03_GPIO_PIN GPIO_Pin_5
#define X03_GPIO GPIO_P1
#define X04 P16
#define X04_GPIO_PIN GPIO_Pin_6
#define X04_GPIO GPIO_P1
#define X05 P17
#define X05_GPIO_PIN GPIO_Pin_7
#define X05_GPIO GPIO_P1
#define X06 P54
#define X06_GPIO_PIN GPIO_Pin_4
#define X06_GPIO GPIO_P5
#define X07 P55
#define X07_GPIO_PIN GPIO_Pin_5
#define X07_GPIO GPIO_P5
#define Input_ON 0 //输入ON
#define Input_OFF 1 //输入OFF
#define OutputT_ON 1 //晶体管输出ON
#define OutputT_OFF 0 //晶体管输出OFF
void GPIO_Config(void);
#endif
接下来,我们来配置一下串口参数,在之前的帖子中我们知道,迪文DGUS屏的串口通信波特率配置的是115200,那么,我们在单片机程序中,自然也要讲串口通信的波特率配置成115200,其他的就不需要修改了:
#include "bsp_usart.h"
/*************** 串口初始化函数 *****************/
void UART_config(void)
{
COMx_InitDefine COMx_InitStructure; //结构定义
COMx_InitStructure.UART_Mode = UART_8bit_BRTx; //模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
COMx_InitStructure.UART_BRT_Use = BRT_Timer2; //使用波特率, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)
COMx_InitStructure.UART_BaudRate = 115200ul; //波特率, 一般 110 ~ 115200
COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLE
COMx_InitStructure.UART_Interrupt = ENABLE; //中断允许, ENABLE或DISABLE
COMx_InitStructure.UART_P_SW = UART1_SW_P30_P31; //切换端口, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17(必须使用内部时钟)
USART_Configuration(USART1, &COMx_InitStructure); //初始化串口1 USART1,USART2
}
程序中有需要用到串口定时向触摸屏刷新数据,所以,这里我们也配置一个定时器,并设置起中断频率为1000Hz,即:1ms中断一次。
#include "bsp_timer.h"
/************************ 定时器配置 ****************************/
void Timer0_config(void)
{
TIM_InitTypeDef TIM_InitStructure; //结构定义
TIM_InitStructure.TIM_Mode = TIM_16BitAutoReload; //指定工作模式, TIM_16BitAutoReload,TIM_16Bit,TIM_8BitAutoReload,TIM_16BitAutoReloadNoMask
TIM_InitStructure.TIM_Polity = PolityLow; //指定中断优先级(低到高) Polity_0,Polity_1,Polity_2,Polity_3
TIM_InitStructure.TIM_Interrupt = ENABLE; //中断是否允许, ENABLE或DISABLE
TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_1T; //指定时钟源, TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
TIM_InitStructure.TIM_ClkOut = DISABLE; //是否输出高速脉冲, ENABLE或DISABLE
TIM_InitStructure.TIM_Value = 65536UL - (MAIN_Fosc / 1000); //初值,
TIM_InitStructure.TIM_Run = ENABLE; //是否初始化后启动定时器, ENABLE或DISABLE
Timer_Inilize(Timer0,&TIM_InitStructure); //初始化Timer0 Timer0,Timer1,Timer2,Timer3,Timer4
}
接下来,我们需要根据板子上的IO分布,来配置一下IO口的输入输出模式,所有输入口均配置成“准双向口”,所有输出口均配置成“强推挽模式”。
#include "bsp_gpio.h"
/************************ IO口配置 ****************************/
void GPIO_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //结构定义
//P10-11口设置为高阻输入
GPIO_InitStructure.Pin = ADC0_GPIO_PIN; //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作
GPIO_InitStructure.Mode = GPIO_HighZ; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(ADC0_GPIO,&GPIO_InitStructure);//初始化
GPIO_InitStructure.Pin = ADC1_GPIO_PIN; //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作
GPIO_InitStructure.Mode = GPIO_HighZ; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(ADC1_GPIO,&GPIO_InitStructure);//初始化
//Y00
GPIO_InitStructure.Pin = Y00_GPIO_PIN; //指定要初始化的IO
GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(Y00_GPIO,&GPIO_InitStructure); //初始化
//Y01
GPIO_InitStructure.Pin = Y01_GPIO_PIN; //指定要初始化的IO
GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(Y01_GPIO,&GPIO_InitStructure); //初始化
//Y02
GPIO_InitStructure.Pin = Y02_GPIO_PIN; //指定要初始化的IO
GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(Y02_GPIO,&GPIO_InitStructure); //初始化
//Y03
GPIO_InitStructure.Pin = Y03_GPIO_PIN; //指定要初始化的IO
GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(Y03_GPIO,&GPIO_InitStructure); //初始化
//Y04
GPIO_InitStructure.Pin = Y04_GPIO_PIN; //指定要初始化的IO
GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(Y04_GPIO,&GPIO_InitStructure); //初始化
//Y05
GPIO_InitStructure.Pin = Y05_GPIO_PIN; //指定要初始化的IO
GPIO_InitStructure.Mode = GPIO_OUT_PP; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(Y05_GPIO,&GPIO_InitStructure); //初始化
//X00
GPIO_InitStructure.Pin = X00_GPIO_PIN; //指定要初始化的IO
GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(X00_GPIO,&GPIO_InitStructure); //初始化
//X01
GPIO_InitStructure.Pin = X01_GPIO_PIN; //指定要初始化的IO
GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(X01_GPIO,&GPIO_InitStructure); //初始化
//X02
GPIO_InitStructure.Pin = X02_GPIO_PIN; //指定要初始化的IO
GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(X02_GPIO,&GPIO_InitStructure); //初始化
//X03
GPIO_InitStructure.Pin = X03_GPIO_PIN; //指定要初始化的IO
GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(X03_GPIO,&GPIO_InitStructure); //初始化
//X04
GPIO_InitStructure.Pin = X04_GPIO_PIN; //指定要初始化的IO
GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(X04_GPIO,&GPIO_InitStructure); //初始化
//X05
GPIO_InitStructure.Pin = X05_GPIO_PIN; //指定要初始化的IO
GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(X05_GPIO,&GPIO_InitStructure); //初始化
//X06
GPIO_InitStructure.Pin = X06_GPIO_PIN; //指定要初始化的IO
GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(X06_GPIO,&GPIO_InitStructure); //初始化
//X07
GPIO_InitStructure.Pin = X07_GPIO_PIN; //指定要初始化的IO
GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(X07_GPIO,&GPIO_InitStructure); //初始化
Y00 = OutputT_OFF;
Y01 = OutputT_OFF;
Y02 = OutputT_OFF;
Y03 = OutputT_OFF;
Y04 = OutputT_OFF;
Y05 = OutputT_OFF;
}
另外,程序中也有用到两路0-5V电压的采集,所以此处我们还需要对ADC相关的参数进行配置,本例程中采用的是AD口分别是P10和P11,查询方式获取AD值:
#include "bsp_adc.h"
/**************** ADC配置函数 *****************/
/*P11 ADC0
/*P10 ADC1
/**********************************************/
void ADC_config(void)
{
ADC_InitTypeDef ADC_InitStructure; //结构定义
ADC_InitStructure.ADC_Px = ADC_P11|ADC_P10; //设置要做ADC的IO, ADC_P10 ~ ADC_P17(或操作),ADC_P1_All
ADC_InitStructure.ADC_Speed = ADC_90T; //ADC速度 ADC_90T,ADC_180T,ADC_360T,ADC_540T
ADC_InitStructure.ADC_Power = ENABLE; //ADC功率允许/关闭 ENABLE,DISABLE
ADC_InitStructure.ADC_AdjResult = ADC_RES_H2L8; //ADC结果调整, ADC_RES_H2L8,ADC_RES_H8L2
ADC_InitStructure.ADC_Polity = PolityLow; //优先级设置 PolityHigh,PolityLow
ADC_InitStructure.ADC_Interrupt = DISABLE; //中断允许 ENABLE,DISABLE
ADC_Inilize(&ADC_InitStructure); //初始化
ADC_PowerControl(ENABLE); //单独的ADC电源操作函数, ENABLE或DISABLE
}
至此,系统配置相关的东西基本就完成了,接下来,我们就需要自己写一些应用相关的函数了,本例中,笔者写了3个函数:
• Uart_Driver(); //串口1驱动函数
• ADC_Sampling(); //ADC采样
• GIOP_StateRefresh();//GPIO状态刷新
其中,Uart_Driver()函数,主要是用对串口中断接收到的数据进行解析及定时发送数据,其中解析数据主要包括:DGUS屏按键返回的指令、参数设置的指令等;定时发送数据内容主要包括:定时向DGUS屏写入数据,比如:数据变量显示、图标变量显示等; ADC_Sampling()函数主要是对外部两路0-5V模拟量输入进行采样处理;
GIOP_StateRefresh()函数主要是用来实时刷新输入输出口的状态。
那么,我们首先来看下Uart_Driver()函数:
/********************* UART数据处理 **********************/
void Uart_Driver(void)
{
if(Uart1_RX_Finish)
{
//根据收到的指令执行相应的动作
if((RX1_Buffer[0]==0x06)&&(RX1_Buffer[1]==0X83)&&(RX1_Buffer[2]==0x00)&&
(RX1_Buffer[3]==0x20)&&(RX1_Buffer[4]==0x01)&&(RX1_Buffer[5]==0x00))//按键返回
{
if(RX1_Buffer[6]==0x01)//Y0
{
Y00 = ~Y00;
}
if(RX1_Buffer[6]==0x02)//Y1
{
Y01 = ~Y01;
}
if(RX1_Buffer[6]==0x03)//Y2
{
Y02 = ~Y02;
}
if(RX1_Buffer[6]==0x04)//Y3
{
Y03 = ~Y03;
}
if(RX1_Buffer[6]==0x05)//Y4
{
Y04 = ~Y04;
}
if(RX1_Buffer[6]==0x06)//Y5
{
Y05 = ~Y05;
}
}
//定时器返回数据:0-99999ms
if((RX1_Buffer[0]==0x08)&&(RX1_Buffer[1]==0X83)&&(RX1_Buffer[2]==0x00)&&(RX1_Buffer[3]==0x10)&&(RX1_Buffer[4]==0x02))//按键返回
{
SetTime = (u32)RX1_Buffer[5]<<24|(u32)RX1_Buffer[6]<<16|(u32)RX1_Buffer[7]<<8|(u32)RX1_Buffer[8];
SetTimeDis = SetTime;
EEPROM_SectorErase(IAP_ADDRESS);//扇区擦除,为写EEPROM做准备
EEPROM_WriteTable[0] = SetTime>>24;
EEPROM_WriteTable[1] = SetTime>>16;
EEPROM_WriteTable[2] = SetTime>>8 ;
EEPROM_WriteTable[3] = SetTime;
EEPROM_WriteTable[4] = 0x01; //参数更新标志
EEPROM_write_n(IAP_ADDRESS,EEPROM_WriteTable,5);//将数据写到EEPROM
}
memset(RX1_Buffer,NULL,sizeof(RX1_Buffer));//清空RX1_Buffer数组
Uart1_RX_Finish = 0;
}
if(Uart1_TX_EN)//每隔指定时间发送一次数据
{
if(!RX_Busy)
{
if(!Uart1_TX_Init)
{
TX1_Buffer[0] = 0x5A;//帧头
TX1_Buffer[1] = 0xA5;//帧头
TX1_Buffer[2] = 0x27;//长度
TX1_Buffer[3] = 0x82;//命令0x82
TX1_Buffer[4] = 0x00;//首地址H
TX1_Buffer[5] = 0x00;//首地址L
TX1_Buffer[6] = 0x00; //X0输入状态H
TX1_Buffer[7] = (u8)X00_State; //X0输入状态L
TX1_Buffer[8] = 0x00; //X1输入状态H
TX1_Buffer[9] = (u8)X01_State; //X1输入状态L
TX1_Buffer[10] = 0x00; //X2输入状态H
TX1_Buffer[11] = (u8)X02_State; //X2输入状态L
TX1_Buffer[12] = 0x00; //X3输入状态H
TX1_Buffer[13] = (u8)X03_State; //X3输入状态L
TX1_Buffer[14] = 0x00; //X4输入状态H
TX1_Buffer[15] = (u8)X04_State; //X4输入状态L
TX1_Buffer[16] = 0x00; //X5输入状态H
TX1_Buffer[17] = (u8)X05_State; //X5输入状态L
TX1_Buffer[18] = 0x00; //X6输入状态H
TX1_Buffer[19] = (u8)X06_State; //X6输入状态L
TX1_Buffer[20] = 0x00; //X7输入状态H
TX1_Buffer[21] = (u8)X07_State; //X7输入状态L
TX1_Buffer[22] = 0x00; //Y0输出状态H
TX1_Buffer[23] = (u8)Y00_State; //Y0输出状态L
TX1_Buffer[24] = 0x00; //Y1输出状态H
TX1_Buffer[25] = (u8)Y01_State; //Y1输出状态L
TX1_Buffer[26] = 0x00; //Y2输出状态H
TX1_Buffer[27] = (u8)Y02_State; //Y2输出状态L
TX1_Buffer[28] = 0x00; //Y3输出状态H
TX1_Buffer[29] = (u8)Y03_State; //Y3输出状态L
TX1_Buffer[30] = 0x00; //Y4输出状态H
TX1_Buffer[31] = (u8)Y04_State; //Y4输出状态L
TX1_Buffer[32] = 0x00; //Y5输出状态H
TX1_Buffer[33] = (u8)Y05_State; //Y5输出状态L
TX1_Buffer[34] = ADC0_Voltage/256;//ADC0电压H
TX1_Buffer[35] = ADC0_Voltage%256;//ADC0电压L
TX1_Buffer[36] = ADC1_Voltage/256;//ADC1电压H
TX1_Buffer[37] = ADC1_Voltage%256;//ADC1电压L
TX1_Buffer[38] = SetTimeDis>>24; //定时时间HH
TX1_Buffer[39] = (SetTimeDis>>16)&0x00FF; //定时时间HL
TX1_Buffer[40] = (SetTimeDis>>8)&0x0000FF;//定时时间LH
TX1_Buffer[41] = SetTimeDis%256; //定时时间LL
Uart1_TX_Init = 1;
COM1.TX_write = 0;
}
if(COM1.TX_write<42)
{
if(COM1.B_TX_busy == 0)
{
COM1.B_TX_busy = 1;
SBUF = TX1_Buffer[COM1.TX_write++]; //发送接收到的字符
}
}
else
{
COM1.RX_Cnt = 0;
Uart1_TX_EN = 0;//数据发送完成,uart1发送数据使能清“0”
}
}
}
}
在这个函数中,主要是串口中断完成数据接收后,对其中两条指令进行解析,第一条指令是关于DGUS屏的点动控制,也就是实现前面介绍的功能,在DGUS屏上,点击Y0按键,板子对应的Y00口输出ON,状态图标变成绿色;再一次点击Y00按键,板子对应的Y00口输出OFF,状态图标变成红色,其他按键及板子上的输出口也按照同样的逻辑执行。
第二条指令,就是一条关于时间参数设置的指令,通过触摸屏设置一个时间参数,下发到单片机,可用过某些应用场合下定时用,比如,定时让一个LED输出ON、OFF,从而实现闪烁效果等。
关于这两条指令每个字节的含义,在前面建DGUS工程时也有说明,在此就不再赘述。
这个串口发送数据的时间间隔可以通过触摸屏设置,这个定时时间是通过定时器0来实现的:
/********************* Timer0中断函数************************/
void timer0_int (void) interrupt TIMER0_VECTOR //1ms
{
adc_msec ++;
uart_msec ++;
if(uart_msec>=SetTime)//串口间隔轮询
{
Uart1_TX_EN = 1;
Uart1_TX_Init = 0;
uart_msec = 0;
}
}
同时,在这个定时器中断函数中,还设定了AD采用的时间间隔,即:100ms进行一次AD采样,然后,为了能让采集到的数据更准确一点,我们通过多次采样求平均值的方式进行处理,当然,还有更多更好的方式,笔者能力有限,也就不好献丑了,在此只给大家提供一个比较简单的处理方式。
/********************* ADC采样 **********************/
void ADC_Sampling(void)
{
if(adc_msec>=100) //每隔100ms采集一次AD数据
{
adc_msec = 0;
ADC0_VALUE_TEMP += Get_ADC10bitResult(1);//通道1-P11
ADC1_VALUE_TEMP += Get_ADC10bitResult(0);//通道0-P10
if(++adc_count>=10)//采集10次数据,求平均值
{
ADC0_VALUE = ADC0_VALUE_TEMP/10; //求出ADC0的AD平均值
ADC1_VALUE = ADC1_VALUE_TEMP/10; //求出ADC1的AD平均值
//将得到的AD值换算成电压值(单位:mV)
ADC0_Voltage = (ADC0_VALUE*5000UL)/1024; //求出ADC0的电压值,单位mV
ADC1_Voltage = (ADC1_VALUE*5000UL)/1024; //求出ADC1的电压值,单位mV
ADC0_VALUE_TEMP = 0;
ADC1_VALUE_TEMP = 0;
adc_count = 0;
}
}
}
最后一个函数,就是GIOP_StateRefresh()IO状态刷新的函数了,这里主要是通过一个比较简单方法,来获取当前板子上的一些输入输出状态,然后通过串口发送到DGUS屏显示。
/********************* IO状态刷新 **********************/
void GIOP_StateRefresh(void)
{
//输入状态刷新
if(X00)X00_State = 0;else X00_State = 1;
if(X01)X01_State = 0;else X01_State = 1;
if(X02)X02_State = 0;else X02_State = 1;
if(X03)X03_State = 0;else X03_State = 1;
if(X04)X04_State = 0;else X04_State = 1;
if(X05)X05_State = 0;else X05_State = 1;
if(X06)X06_State = 0;else X06_State = 1;
if(X07)X07_State = 0;else X07_State = 1;
//输出状态刷新
if(!Y00)Y00_State = 0;else Y00_State = 1;
if(!Y01)Y01_State = 0;else Y01_State = 1;
if(!Y02)Y02_State = 0;else Y02_State = 1;
if(!Y03)Y03_State = 0;else Y03_State = 1;
if(!Y04)Y04_State = 0;else Y04_State = 1;
if(!Y05)Y05_State = 0;else Y05_State = 1;
}
笔者能力有限,所以在本例中使用的都是一些比较笨的办法,但是笔者相信大家肯定会有更多更好的办法来实现该项目的功能,欢迎大家站内私信或者向直接通过论坛问答频道向笔者提问。
最后,也就是本项目中比较关键的一个知识点,那就是关于DGUS屏的指令的接收处理,在前面介绍有介绍过迪文DGUS屏的指令构成:

本例中,DGUS工程配置的时候,就将帧头设置成了5A A5,由于没有启用CRC校验,因此,我们也不需要关注CRC校验。对于接收迪文DGUS指令的思路是这样的:
先判断帧头,如果帧头验证成功了,就意味着是DGUS屏在下发指令,接下来,就要判断数据的长度,所以这个长度位Len就要起到比较关键的作用了,这个长度位Len本身就是指后面跟随数据的总长度,因为,我们只需要在接收到Len个数据后,就可以认为是接收完成了,而后即时在接收到数据也不管了。当然,除非后面的数据又是以5A A5开头的,也就意味着是一帧新的数据的到来。
/********************* UART1中断函数 ************************/
void UART1_int (void) interrupt UART1_VECTOR
{
static bit RX_5A_OK = 0;
static bit RX_A5_OK = 0;
static u8 UART1_DataTemp = 0;
if(RI)
{
RI = 0;
UART1_DataTemp = SBUF;
RX_Busy = 1; //接收忙
if(RX_5A_OK)
{
if(RX_A5_OK)
{
RX1_Buffer[COM1.RX_Cnt++] = UART1_DataTemp; //将接收到的数组暂存到RX1_Buffer数组
if(COM1.RX_Cnt == RX1_Buffer[0] + 1) //接收完成
{
Uart1_RX_Finish = 1; //数据接收完成,将标志位置1
RX_5A_OK = 0;
RX_A5_OK = 0;
RX_Busy = 0; //接收忙清零
}
}
else
{
if(UART1_DataTemp == 0xA5)
{
RX_A5_OK = 1;
COM1.RX_Cnt = 0;
}
}
}
else
{
if(UART1_DataTemp == 0x5A)
{
RX_5A_OK = 1;
}
}
if(COM1.RX_Cnt >= COM_RX1_Lenth) COM1.RX_Cnt = 0;
}
if(TI)
{
TI = 0;
COM1.B_TX_busy = 0;
}
}
在串口接收数据完成之后,会让一个变量Uart1RXFinish置1,然后再Uart1_Monitor()函数中,一旦检测到Uart1RXFinish为1后,就开始解析数据,解析完成后,将标志位Uart1RXFinish清零。这样一来,就实现了对DGUS屏指令的接收及解析。

至此,整个项目就完成了,只需把代码下载到板子中,并将板子跟DGUS屏连接起来,就能看到项目要实现的效果了。在后续的操作文章中,笔者将会给大家介绍更多DGUS屏和单片机的相关操作,敬请期待!