SingleYork 发表于 2025-5-5 21:00:24

15系列单片机与迪文DGUS屏应用之(六):单片机程序编写

<p>相信接触过STC15系列单片机的小伙伴们,应该会对其编程风格比较熟悉,没错,STC15系列单片机可以采用库函数编程,官方提供了标准的函数库,我们只需要利用好库函数,便可大大简化配置流程,从而提高编程效率。由于笔者这里的教程不是关于51单片机的基础教程,所以此处省去了新建工程以及如何添加库文件等操作。</p>
<p>首先,我们要养成良好的习惯,在使用任何一款板子的时候,先建一个配置板载资源的文件,当然要是板子比较复杂的话,可以分模块配置多个,由于笔者使用的板子比较简单,所以就只添加了为“bsp_gpio.h”和“bsp_gpio.c”的文件,顾名思义,就是一些输入输出的配置而已了。</p>
<pre><code>#ifndef        __BSP_GPIO_H__
#define        __BSP_GPIO_H__

#include        &quot;GPIO.h&quot;

/****************** 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

</code></pre>
<p>接下来,我们来配置一下串口参数,在之前的帖子中我们知道,迪文DGUS屏的串口通信波特率配置的是115200,那么,我们在单片机程序中,自然也要讲串口通信的波特率配置成115200,其他的就不需要修改了:</p>
<pre><code>#include        &quot;bsp_usart.h&quot;

/***************串口初始化函数 *****************/
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, &amp;COMx_InitStructure);                //初始化串口1 USART1,USART2
}

</code></pre>
<p>程序中有需要用到串口定时向触摸屏刷新数据,所以,这里我们也配置一个定时器,并设置起中断频率为1000Hz,即:1ms中断一次。</p>
<pre><code>#include        &quot;bsp_timer.h&quot;

/************************ 定时器配置 ****************************/
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,&amp;TIM_InitStructure);                                        //初始化Timer0          Timer0,Timer1,Timer2,Timer3,Timer4
}

</code></pre>
<p>接下来,我们需要根据板子上的IO分布,来配置一下IO口的输入输出模式,所有输入口均配置成“准双向口”,所有输出口均配置成“强推挽模式”。</p>
<pre><code>#include        &quot;bsp_gpio.h&quot;

/************************ 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,&amp;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,&amp;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,&amp;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,&amp;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,&amp;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,&amp;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,&amp;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,&amp;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,&amp;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,&amp;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,&amp;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,&amp;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,&amp;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,&amp;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,&amp;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,&amp;GPIO_InitStructure); //初始化
   
    Y00 = OutputT_OFF;
    Y01 = OutputT_OFF;
    Y02 = OutputT_OFF;
    Y03 = OutputT_OFF;
    Y04 = OutputT_OFF;
    Y05 = OutputT_OFF;
}

</code></pre>
<p>另外,程序中也有用到两路0-5V电压的采集,所以此处我们还需要对ADC相关的参数进行配置,本例程中采用的是AD口分别是P10和P11,查询方式获取AD值:</p>
<pre><code>#include        &quot;bsp_adc.h&quot;

/**************** 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(&amp;ADC_InitStructure);                                        //初始化

        ADC_PowerControl(ENABLE);                                                        //单独的ADC电源操作函数, ENABLE或DISABLE
}


</code></pre>
<p>至此,系统配置相关的东西基本就完成了,接下来,我们就需要自己写一些应用相关的函数了,本例中,笔者写了3个函数:</p>
<p>• Uart_Driver(); //串口1驱动函数<br />
• ADC_Sampling(); //ADC采样<br />
• GIOP_StateRefresh();//GPIO状态刷新</p>
<p>其中,Uart_Driver()函数,主要是用对串口中断接收到的数据进行解析及定时发送数据,其中解析数据主要包括:DGUS屏按键返回的指令、参数设置的指令等;定时发送数据内容主要包括:定时向DGUS屏写入数据,比如:数据变量显示、图标变量显示等; ADC_Sampling()函数主要是对外部两路0-5V模拟量输入进行采样处理;<br />
GIOP_StateRefresh()函数主要是用来实时刷新输入输出口的状态。</p>
<p>那么,我们首先来看下Uart_Driver()函数:</p>
<pre><code>/*********************   UART数据处理**********************/
void Uart_Driver(void)
{
    if(Uart1_RX_Finish)
    {
      //根据收到的指令执行相应的动作
      if((RX1_Buffer==0x06)&amp;&amp;(RX1_Buffer==0X83)&amp;&amp;(RX1_Buffer==0x00)&amp;&amp;
         (RX1_Buffer==0x20)&amp;&amp;(RX1_Buffer==0x01)&amp;&amp;(RX1_Buffer==0x00))//按键返回
      {
            if(RX1_Buffer==0x01)//Y0
            {
                Y00 = ~Y00;
            }
            if(RX1_Buffer==0x02)//Y1
            {
                Y01 = ~Y01;
            }
            if(RX1_Buffer==0x03)//Y2
            {
                Y02 = ~Y02;
            }
            if(RX1_Buffer==0x04)//Y3
            {
                Y03 = ~Y03;
            }
            if(RX1_Buffer==0x05)//Y4
            {
                Y04 = ~Y04;
            }
            if(RX1_Buffer==0x06)//Y5
            {
                Y05 = ~Y05;
            }
      }
      //定时器返回数据:0-99999ms
      if((RX1_Buffer==0x08)&amp;&amp;(RX1_Buffer==0X83)&amp;&amp;(RX1_Buffer==0x00)&amp;&amp;(RX1_Buffer==0x10)&amp;&amp;(RX1_Buffer==0x02))//按键返回
      {
            SetTime    = (u32)RX1_Buffer&lt;&lt;24|(u32)RX1_Buffer&lt;&lt;16|(u32)RX1_Buffer&lt;&lt;8|(u32)RX1_Buffer;
            SetTimeDis = SetTime;
      
            EEPROM_SectorErase(IAP_ADDRESS);//扇区擦除,为写EEPROM做准备

            EEPROM_WriteTable = SetTime&gt;&gt;24;
            EEPROM_WriteTable = SetTime&gt;&gt;16;
            EEPROM_WriteTable = SetTime&gt;&gt;8 ;
            EEPROM_WriteTable = SetTime;
   
            EEPROM_WriteTable = 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= 0x5A;//帧头
                TX1_Buffer= 0xA5;//帧头
                TX1_Buffer= 0x27;//长度
                TX1_Buffer= 0x82;//命令0x82
            
                TX1_Buffer= 0x00;//首地址H
                TX1_Buffer= 0x00;//首地址L
            
                TX1_Buffer= 0x00;          //X0输入状态H
                TX1_Buffer= (u8)X00_State; //X0输入状态L
            
                TX1_Buffer= 0x00;          //X1输入状态H
                TX1_Buffer= (u8)X01_State; //X1输入状态L
            
                TX1_Buffer = 0x00;          //X2输入状态H
                TX1_Buffer = (u8)X02_State; //X2输入状态L
            
                TX1_Buffer = 0x00;          //X3输入状态H
                TX1_Buffer = (u8)X03_State; //X3输入状态L
            
                TX1_Buffer = 0x00;          //X4输入状态H
                TX1_Buffer = (u8)X04_State; //X4输入状态L
            
                TX1_Buffer = 0x00;          //X5输入状态H
                TX1_Buffer = (u8)X05_State; //X5输入状态L
            
                TX1_Buffer = 0x00;          //X6输入状态H
                TX1_Buffer = (u8)X06_State; //X6输入状态L
            
                TX1_Buffer = 0x00;          //X7输入状态H
                TX1_Buffer = (u8)X07_State; //X7输入状态L
            
                TX1_Buffer = 0x00;          //Y0输出状态H
                TX1_Buffer = (u8)Y00_State; //Y0输出状态L
            
                TX1_Buffer = 0x00;          //Y1输出状态H
                TX1_Buffer = (u8)Y01_State; //Y1输出状态L
            
                TX1_Buffer = 0x00;          //Y2输出状态H
                TX1_Buffer = (u8)Y02_State; //Y2输出状态L
            
                TX1_Buffer = 0x00;          //Y3输出状态H
                TX1_Buffer = (u8)Y03_State; //Y3输出状态L
            
                TX1_Buffer = 0x00;          //Y4输出状态H
                TX1_Buffer = (u8)Y04_State; //Y4输出状态L
            
                TX1_Buffer = 0x00;          //Y5输出状态H
                TX1_Buffer = (u8)Y05_State; //Y5输出状态L
            
                TX1_Buffer = ADC0_Voltage/256;//ADC0电压H
                TX1_Buffer = ADC0_Voltage%256;//ADC0电压L
            
                TX1_Buffer = ADC1_Voltage/256;//ADC1电压H
                TX1_Buffer = ADC1_Voltage%256;//ADC1电压L
            
                TX1_Buffer = SetTimeDis&gt;&gt;24;          //定时时间HH
                TX1_Buffer = (SetTimeDis&gt;&gt;16)&amp;0x00FF; //定时时间HL
                TX1_Buffer = (SetTimeDis&gt;&gt;8)&amp;0x0000FF;//定时时间LH
                TX1_Buffer = SetTimeDis%256;          //定时时间LL
            
                Uart1_TX_Init= 1;
                COM1.TX_write= 0;
            }
      
            if(COM1.TX_write&lt;42)
            {
                if(COM1.B_TX_busy == 0)
                {
                  COM1.B_TX_busy = 1;
                  SBUF = TX1_Buffer;      //发送接收到的字符
                }
            }
            else
            {
                COM1.RX_Cnt   = 0;
                Uart1_TX_EN   = 0;//数据发送完成,uart1发送数据使能清“0”
            }
      }
    }
}

</code></pre>
<p>在这个函数中,主要是串口中断完成数据接收后,对其中两条指令进行解析,第一条指令是关于DGUS屏的点动控制,也就是实现前面介绍的功能,在DGUS屏上,点击Y0按键,板子对应的Y00口输出ON,状态图标变成绿色;再一次点击Y00按键,板子对应的Y00口输出OFF,状态图标变成红色,其他按键及板子上的输出口也按照同样的逻辑执行。</p>
<p>第二条指令,就是一条关于时间参数设置的指令,通过触摸屏设置一个时间参数,下发到单片机,可用过某些应用场合下定时用,比如,定时让一个LED输出ON、OFF,从而实现闪烁效果等。</p>
<p>关于这两条指令每个字节的含义,在前面建DGUS工程时也有说明,在此就不再赘述。</p>
<p>这个串口发送数据的时间间隔可以通过触摸屏设置,这个定时时间是通过定时器0来实现的:</p>
<pre><code>/********************* Timer0中断函数************************/
void timer0_int (void) interrupt TIMER0_VECTOR //1ms
{
    adc_msec++;
    uart_msec ++;

    if(uart_msec&gt;=SetTime)//串口间隔轮询
    {
      Uart1_TX_EN   = 1;
      Uart1_TX_Init = 0;
      uart_msec   = 0;
    }
}

</code></pre>
<p>同时,在这个定时器中断函数中,还设定了AD采用的时间间隔,即:100ms进行一次AD采样,然后,为了能让采集到的数据更准确一点,我们通过多次采样求平均值的方式进行处理,当然,还有更多更好的方式,笔者能力有限,也就不好献丑了,在此只给大家提供一个比较简单的处理方式。</p>
<pre><code>/*********************   ADC采样   **********************/
void ADC_Sampling(void)
{
    if(adc_msec&gt;=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&gt;=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;
      }
    }
}

</code></pre>
<p>最后一个函数,就是GIOP_StateRefresh()IO状态刷新的函数了,这里主要是通过一个比较简单方法,来获取当前板子上的一些输入输出状态,然后通过串口发送到DGUS屏显示。</p>
<pre><code>/*********************    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;
}

</code></pre>
<p>笔者能力有限,所以在本例中使用的都是一些比较笨的办法,但是笔者相信大家肯定会有更多更好的办法来实现该项目的功能,欢迎大家站内私信或者向直接通过论坛问答频道向笔者提问。</p>
<p>最后,也就是本项目中比较关键的一个知识点,那就是关于DGUS屏的指令的接收处理,在前面介绍有介绍过迪文DGUS屏的指令构成:</p>
<p><img src="data/attachment/forum/202505/05/205859x0p7spv0111wyfp3.png" alt="6-12.png" title="6-12.png" /></p>
<p>本例中,DGUS工程配置的时候,就将帧头设置成了5A A5,由于没有启用CRC校验,因此,我们也不需要关注CRC校验。对于接收迪文DGUS指令的思路是这样的:</p>
<p>先判断帧头,如果帧头验证成功了,就意味着是DGUS屏在下发指令,接下来,就要判断数据的长度,所以这个长度位Len就要起到比较关键的作用了,这个长度位Len本身就是指后面跟随数据的总长度,因为,我们只需要在接收到Len个数据后,就可以认为是接收完成了,而后即时在接收到数据也不管了。当然,除非后面的数据又是以5A A5开头的,也就意味着是一帧新的数据的到来。</p>
<pre><code>/********************* UART1中断函数 ************************/
void UART1_int (void) interrupt UART1_VECTOR
{
        static bit RX_5A_OK = 0;
    static bit RX_A5_OK = 0;
    static u8UART1_DataTemp = 0;

    if(RI)
        {
                RI = 0;
   
      UART1_DataTemp = SBUF;
      RX_Busy            = 1;        //接收忙
   
      if(RX_5A_OK)
                {
                        if(RX_A5_OK)
                        {
                                RX1_Buffer = UART1_DataTemp;      //将接收到的数组暂存到RX1_Buffer数组
               
                                if(COM1.RX_Cnt == RX1_Buffer + 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 &gt;= COM_RX1_Lenth)        COM1.RX_Cnt = 0;
        }

        if(TI)
        {
                TI = 0;
      COM1.B_TX_busy = 0;
        }
}


</code></pre>
<p>在串口接收数据完成之后,会让一个变量Uart1RXFinish置1,然后再Uart1_Monitor()函数中,一旦检测到Uart1RXFinish为1后,就开始解析数据,解析完成后,将标志位Uart1RXFinish清零。这样一来,就实现了对DGUS屏指令的接收及解析。</p>
<p><img src="data/attachment/forum/202505/05/210011nia6whzizel957s3.png" alt="00.png" title="00.png" /></p>
<p>至此,整个项目就完成了,只需把代码下载到板子中,并将板子跟DGUS屏连接起来,就能看到项目要实现的效果了。在后续的操作文章中,笔者将会给大家介绍更多DGUS屏和单片机的相关操作,敬请期待!</p>
页: [1]
查看完整版本: 15系列单片机与迪文DGUS屏应用之(六):单片机程序编写