• ESP8266与STC8H8K单片机联动——天气时钟


    基于ESP8266与STC单片机的天气时钟(包括DS18B20、TFT、串口、外部中断、ESP8266、STC、API等)

    一、设计背景

    本人经过这学期课程学习,虽然熟练了51单片机的使用,但是仅仅局限于不同模块的使用,并没有将模块与模块之间联动起来,此次借着期末大作业的机会,本人将模块之间的联动延伸至单片机之间的联动,这些年火热的“物联网”、“万物互联”等名词促使本人除了STC8H8K64U外,选择了ESP8266NodeMCU这块单片机来完成第一步——两物互连。一个多功能显示的智慧屏幕方便人们生活,减少获取信息的流程。

    二、设计目标

    1. 实现STC8H8K64U与ESP8266NodeMCU串口通信
    2. 让ESP8266NodeMCU成功连接WiFi
    3. 利用ESP8266NodeMCU获取区域天气、温度和时间等信息
    4. 在STC8H8K64U上实现DS18B20实时检测环境温度
    5. 利用STC8H8K64U将所有数据传输至TFT并显示
    6. 利用外部中断按键控制TFT显示屏的亮灭

    三、框图以及部分连接方式

    在这里插入图片描述

    STC的TXD与RXD口反接ESP8266TXD和RXD

    在这里插入图片描述
    在这里插入图片描述

    单片机于TFT彩屏对应接口

    在这里插入图片描述

    DS18B20

    在这里插入图片描述

    四、单片机及模块功能介绍

    1、STC8H8K64U
    STC8H8K64U是本学期一直使用的以超强抗干扰、低价、高速、低功耗为目标的8051单片机(8位机),此项目中大部分的数据接收、处理在此单片机上进行。

    2、 ESP8266NodeMCU
    ESP8266NodeMCU是一款集成了Wifi功能的MCU开发板(32位机),可以直接连接wifi,开发环境多元化,也是表较受欢迎的物联网芯片。在此项目中主要使用ESP8266连接到电脑热点(已联网),然后借助网络利用心知天气的API,获取时间、天气、地区温度等信息。

    3、 DS18B20
    DS18B20是一款常用的高精度的单总线数字温度测量芯片。具有体积小,硬件开销低,抗干扰能力强,精度高的特点。在此项目中,DS18B20与STC8H8K64U配合实时测量环境温度。

    4、TFT液晶显示器
    TFT液晶显示器主要的构成包括:萤光管、导光板、偏光板、滤光板、玻璃基板、配向膜、液晶材料、薄模式晶体管等。在此项目中,使用的是1.44寸TFT彩屏(IIC协议),用于显示单片机发送过来的数据信息,包括显示图片、地区、温度、天气文字信息。

    Img2Lcd软件
    在这里插入图片描述

    5、 DS18B20作为温度对比
    先前已经在TFT屏幕上显示出区域温度,后续增加一个环境温度更加人性化,显示室温。单总线的DS18B20操作较为简单,注意好延时和数据格式即可。DS18B20精度为11位,且分为两个字节存储,在最后获取数据时需要把高位左移8位后再或低8位,然后乘以0.625(为了保留一位小数点),将每一位取出来放到数组中,在TFT显示的时候数组每一位加0x30转化位字符串形式,成功显示。

    DS18B20数据存储格式
    在这里插入图片描述

    代码

    由于TFT函数以及其他头文件和ESP8266的库文件太多,我已打包上传,欢迎各位前往主页下载。

    ESP8266主函数代码(不包含库的部分)

    #include <ESP8266WiFi.h>                    //ESP8266自带库,无需安装
    #include <ESP8266_Seniverse.h>              //https://github.com/taichi-maker/ESP8266-Seniverse
    #include <WiFiUdp.h>
    #include <NTPClient.h>
    const char* ssid     = "xxxxxxxxx";       // 连接WiFi名(输入自己的WiFi名)
                                               
    const char* password = "xxxxxxxxx";          // 连接WiFi密码(输入自己的WiFi密码)
                                              
    
    // 心知天气HTTP请求所需信息
    // 请对以下信息进行修改,填入您的心知天气私钥以及需要获取天气信息的城市和温度单位
    // 如需进一步了解心知天气API所提供的城市列表等信息,请前往心知天气官方产品文档网址:
    // https://www.seniverse.com/docs
    const char* reqUserKey = "StYr2Swd9ftD4b7-H";   // 私钥
    const char* reqLocation = "shenzhen";            // 城市,可使用"ip"自动识别请求 IP 地址
    const char* reqUnit = "c";                      // 摄氏(c)/华氏(f)
    
    WiFiUDP ntpUDP;
    NTPClient timeClient(ntpUDP, "ntp.aliyun.com"); //NTP地址
    
    WeatherNow weatherNow;  // 建立WeatherNow对象用于获取心知天气信息
    
    void setup(){
      Serial.begin(9600);          
      Serial.println("");
    
      connectWiFi();    // 连接wifi
    
      // 配置心知天气请求信息
      weatherNow.config(reqUserKey, reqLocation, reqUnit);
    
      timeClient.begin();
      timeClient.setTimeOffset(28800); //+1区,偏移3600,+8区,偏移3600*8
    }
     
    void loop(){
    
      if(weatherNow.update()){  // 更新天气信息
        //Serial.println(F("======Weahter Info======"));(由于我要从串口发数据过去,测试的时候输出提示,传输的时候就把这些提示都注释了)
        //Serial.print("Server Response: ");
        //Serial.println(weatherNow.getServerCode()); // 获取服务器响应码
        //Serial.print(F("Weather Now: "));
        Serial.println(weatherNow.getWeatherText());  // 获取当前天气(字符串格式)
        //Serial.print(F(" "));
        //Serial.println(weatherNow.getWeatherCode());// 获取当前天气(整数格式)
        //Serial.print(F("Temperature: "));
        Serial.println(weatherNow.getDegree());     // 获取当前温度数值
        //Serial.print(F("Last Update: "));
        //Serial.println(weatherNow.getLastUpdate()); // 获取服务器更新天气信息时间(不知道为什么我的电脑获取时间不正确,时间戳不对,所以换了下面的方法获取时间)
        //Serial.println(F("========================"));     
      } else {    // 更新失败
        //Serial.println("Update Fail...");   
        //Serial.print("Server Response: ");          // 输出服务器响应状态码供用户查找问题
        //Serial.println(weatherNow.getServerCode()); // 心知天气服务器错误代码说明可通过以下网址获取
      }                                             // https://docs.seniverse.com/api/start/error.html
    
      timeClient.update();
      unsigned long epochTime = timeClient.getEpochTime();
      //打印时间
      int currentHour = timeClient.getHours();
      Serial.print(currentHour);
      Serial.print(F(":"));
      int currentMinute = timeClient.getMinutes();
      Serial.println(currentMinute);
    
      delay(500);
    }
    
    // 连接WiFi
    void connectWiFi(){
      WiFi.begin(ssid, password);                  // 启动网络连接
      Serial.print("Connecting to ");              // 串口监视器输出网络连接信息
      Serial.print(ssid); Serial.println(" ...");  // 告知用户NodeMCU正在尝试WiFi连接
      
      int i = 0;                                   // 这一段程序语句用于检查WiFi是否连接成功
      while (WiFi.status() != WL_CONNECTED) {      // WiFi.status()函数的返回值是由NodeMCU的WiFi连接状态所决定的。 
        delay(1000);                               // 如果WiFi连接成功则返回值为WL_CONNECTED                       
        Serial.print(i++); Serial.print(' ');      // 此处通过While循环让NodeMCU每隔一秒钟检查一次WiFi.status()函数返回值
      }                                            // 同时NodeMCU将通过串口监视器输出连接时长读秒。
                                                   // 这个读秒是通过变量i每隔一秒自加1来实现的。                                              
      Serial.println("");                          // WiFi连接成功后
      Serial.println("Connection established!");   // NodeMCU将通过串口监视器输出"连接成功"信息。
      Serial.print("IP address:    ");             // 同时还将输出NodeMCU的IP地址。这一功能是通过调用
      Serial.println(WiFi.localIP());              // WiFi.localIP()函数来实现的。该函数的返回值即NodeMCU的IP地址。  
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86

    上面这部分需要注意的是,由于获取心知天气时间戳有问题,只有每次烧录的时候从才能更新时间,而且慢5-15分钟,所以我的时间获取采用了另外的方法

    STC8H8K主函数代码

    #include<stc8h.h>
    #include<intrins.h>
    #include<TFT.h>
    #include<string.h>
    #include<image.h>
    #include<onewire.h>
    
    #define uchar unsigned char
    #define uint unsigned int
    bit busy;
    
    sbit DQ = P3^3;  //单总线接口
    
    uchar j = 0;
    uchar i = 0;
    
    
    char xdata tem[3][15];
    char Rev[15];
    int datacount;
    unsigned int templen;
    
    uint flag = 0;//定时器计数
    uchar sec = 15,min = 20,hour = 8;
    
    uchar code t_display[]={                       //标准字库
    //   0    1    2    3    4    5    6    7    8    9    
        0x3F,0x06,0x5B,0x4F,0x66,0x6D,0x7D,0x07,0x7F,0x6F,
        0xBF,0x86,0xDB,0xCF,0xE6,0xED,0xFD,0x87,0xFF,0xEF,0x00,0x40};    //0. 1. 2. 3. 4. 5. 6. 7. 8. 9.  -
    
    uchar code T_COM[]={0x01,0x02,0x04,0x08,0x10,0x20,0x40,0x80};      //位码
    
    void DS18B20_Reset();
    void DS18B20_WriteByte(u8 dat);
    u8 DS18B20_ReadByte();
    
    void delay_us(u8 us);
    u16 ReadTemperature();
    void DisplayTemperature(u16 temp);
    
    
    void Delay1ms()		//@11.0592MHz
    {
    	unsigned char i, j;
    
    	i = 15;
    	j = 90;
    	do
    	{
    		while (--j);
    	} while (--i);
    }
    
    void Nixie(uchar i, uint j)
    {
    	P7=~T_COM[i];
    	P6=~t_display[j];
    	Delay1ms();
    	P6 = 0xFF;
    }
    
    
    /*----------------------------
    gpio初始化为准双向口
    ----------------------------*/
    void gpio()	
    {
        P0M1 = 0x00;   P0M0 = 0x00;   //设置为准双向口
        P1M1 = 0x00;   P1M0 = 0x00;   //设置为准双向口
        P2M1 = 0x00;   P2M0 = 0x00;   //设置为准双向口
        P3M1 = 0x00;   P3M0 = 0x00;   //设置为准双向口
        P4M1 = 0x00;   P4M0 = 0x00;   //设置为准双向口
        P5M1 = 0x00;   P5M0 = 0x00;   //设置为准双向口
        P6M1 = 0x00;   P6M0 = 0x00;   //设置为准双向口
        P7M1 = 0x00;   P7M0 = 0x00;   //设置为准双向口
    }
    
    
    /*----------------------------
    发送字节
    ----------------------------*/
    void SendData(uchar dat)
    {
        while (busy);               
        busy = 1;
        SBUF = dat;                 //要发送的数据存入SBUF
    }
    
    
    /*----------------------------
    UART1初始化
    -----------------------------*/
    void InitUART(void)
    {
        SCON = 0x50;                //8位数据	
    	P_SW1= P_SW1 & 0x3F; 
        AUXR |= 0x40;                //定时器1T模式
    	AUXR &= 0xFE;	
        TMOD &= 0x0F;
        TMOD |= 0x20;                //8位自动重装载模式
        TL1 = 0xDC;   				//
        TH1 = 0xDC;
        TR1 = 1;                    //开启定时器1
        ES = 1;                     //开启串口中断
        EA = 1;
    
    }
    
    uchar menu[4];
    uchar DS18TFT[5];
    void main(void)
    {
    	unsigned int temp = 0;
    	unsigned char i = 0;
    	unsigned char flag = 1;
    	uchar select = 1;
    	gpio();		//gpio初始化
    	InitUART();	 //串口初始化
    	initTFT();	//初始化TFT
    	//Timer0Init();	//定时器0初始化
    	renovateTFT(WHITE);	//用白色刷新屏幕
    	bl=1;	 	//打开屏幕灯
    	showimage(gImage_1);
    	IT0=1;//跳沿触发
    	EX0=1;
    	for(i=0;i<15;i++)
    	{
    		tem[0][i]=' ';
    		tem[1][i]=' ';
    		tem[2][i]=' ';
    	}
    
    	tem[1][3] = 'C';		//温度只有两位数,把第三位预设为摄氏度单位
    	DS18TFT[4] = 'C';
    	
      	while(1)
      	{	
    		temp = ReadTemperature();  
    		/*        
    		menu[0] = temp/100;
    		menu[1] = temp%100/10 + 10;	//+10是为了数码管显示出点
    		menu[2] = temp%10;
    		Nixie(2,menu[0]);
    		Nixie(1,menu[1]);
    		Nixie(0,menu[2]);
    		*/
    		DS18TFT[0] = temp/100 + 0x30;
    		DS18TFT[1] = temp%100/10 + 0x30;
    		DS18TFT[2] = '.';
    		DS18TFT[3] = temp%10 + 0x30;
    		
    		//displayASCII8X16(10, 0, time, 16, BLACK, WHITE);
    		displayASCII8X16(10, 0, tem[2], 6 , BLACK, WHITE);
    		displayASCII8X16(60, 0, "ShenZhen ", 9, BLACK, WHITE);
    		displayASCII8X16(10, 20, "weather:", 9, BLACK, WHITE);
    		displayASCII8X16(10, 40, tem[0], 10, BLACK, WHITE);
    		displayASCII8X16(10, 60, "tempture:", 9, BLACK, WHITE);
    		displayASCII8X16(10, 80, tem[1], 4, BLACK, WHITE);
    		displayASCII8X16(50, 80, DS18TFT, 5, BLACK, WHITE);
    		
    
    		
    	}
    }
    
    
    /*----------------------------
    UART 中断
    -----------------------------*/
    void Uart() interrupt 4 using 1
    {
    
    	uchar temp;
    	uchar i=0;
        if (RI)
        {
            RI = 0;                 //接收到字符后,RI清0
    		P40=0;
            temp = SBUF; 
    		if(temp!='\n')
    		{
    			Rev[datacount] = temp;
    			datacount++;
    		}else
    		{
    			templen = datacount;
    			datacount = 0;
    			
    			if(templen==3)
    			{
    				tem[1][0] = Rev[0];
    				tem[1][1] = Rev[1];
    				tem[1][2] = Rev[2];
    			}else if((Rev[0]-48)<=9)
    			{
    				tem[2][0] = Rev[0];
    				tem[2][1] = Rev[1];
    				tem[2][2] = Rev[2];
    				tem[2][3] = Rev[3];
    				tem[2][4] = Rev[4];
    			}else
    			{
    				for(i=0;i<10;i++)
    				{
    					tem[0][i] = Rev[i];
    				}
    			}
    		}
    
        }
        if (TI)
        {
            TI = 0;                 //发送完字符后TI清0
            busy = 0;               //发送完一个字符后busy清0
        }
    }
    
    void delay_us(u8 us)
    {
        do{
            _nop_();_nop_();
    		_nop_();_nop_();
        }while(--us);
    }
    
    /**************************************
    复位DS18B20,并检测设备是否存在
    **************************************/
    void DS18B20_Reset()
    {
        CY = 1;
        while (CY)
        {
            DQ = 0;                     //送出低电平复位信号
            delay_us(240);              //延时至少480us
            delay_us(240);
            DQ = 1;                     //释放数据线
            delay_us(60);               //等待60us
            CY = DQ;                    //检测存在脉冲
            delay_us(240);              //等待设备释放数据线
            delay_us(180);
        }
    }
    
    /**************************************
    从DS18B20读1字节数据
    **************************************/
    u8 DS18B20_ReadByte()
    {
        u8 i;
        u8 dat = 0;
    
        for (i=0; i<8; i++)             //8位计数器
        {
            dat >>= 1;
            DQ = 0;                     //开始时间片
            delay_us(1);                //延时等待
            DQ = 1;                     //准备接收
            delay_us(1);                //接收延时
            if (DQ) dat |= 0x80;        //读取数据
            delay_us(60);               //等待时间片结束
        }
    
        return dat;
    }
    
    /**************************************
    向DS18B20写1字节数据
    **************************************/
    void DS18B20_WriteByte(u8 dat)
    {
        char i;
    
        for (i=0; i<8; i++)             //8位计数器
        {
            DQ = 0;                     //开始时间片
            delay_us(1);                //延时等待
            dat >>= 1;                  //送出数据
            DQ = CY;
            delay_us(60);               //等待时间片结束
            DQ = 1;                     //恢复数据线
            delay_us(1);                //恢复延时
        }
    }
    
    //========================================================================
    // 函数: u16 ReadTemperature()
    // 描述: 读取温度函数。
    // 参数: none.
    // 返回: 温度值.
    //========================================================================
    u16 ReadTemperature()
    {
        u16 TempH, TempL, Temperature;
    	
        DS18B20_Reset();                //设备复位
        DS18B20_WriteByte(0xCC);        //跳过ROM命令
        DS18B20_WriteByte(0x44);        //开始转换命令
        while (!DQ);                    //等待转换完成
    
        DS18B20_Reset();                //设备复位
        DS18B20_WriteByte(0xCC);        //跳过ROM命令
        DS18B20_WriteByte(0xBE);        //读暂存存储器命令
        TempL = DS18B20_ReadByte();     //读温度低字节
        TempH = DS18B20_ReadByte();     //读温度高字节
    	
        if(TempH & 0xf8)    //判断是否位负数
        {
            MinusFlag = 1;  //设置负数标志
            Temperature = (TempH<<8) | TempL;
            Temperature = ~Temperature + 1;
            Temperature *= 0.625;       //0.0625 * 10,保留1位小数点
        }
        else
        {
            MinusFlag = 0;  //清除负数标志
            Temperature = (((TempH<<8) | TempL) * 0.625); //0.0625 * 10,保留1位小数点
        }
    
        return Temperature;
    }
    
    void INT0()		interrupt 0
    {
    	flag++;		//每按下一次就加1
    	
    	if(flag==2)
    	{
    		flag = 0;
    	}
    	if(flag == 1)
    	{
    		bl = 0;
    	}else
    	{
    		bl = 1;
    	}
    	
    	for(i=0;i<20;i++)
    	{
    		Delay1ms();
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50
    • 51
    • 52
    • 53
    • 54
    • 55
    • 56
    • 57
    • 58
    • 59
    • 60
    • 61
    • 62
    • 63
    • 64
    • 65
    • 66
    • 67
    • 68
    • 69
    • 70
    • 71
    • 72
    • 73
    • 74
    • 75
    • 76
    • 77
    • 78
    • 79
    • 80
    • 81
    • 82
    • 83
    • 84
    • 85
    • 86
    • 87
    • 88
    • 89
    • 90
    • 91
    • 92
    • 93
    • 94
    • 95
    • 96
    • 97
    • 98
    • 99
    • 100
    • 101
    • 102
    • 103
    • 104
    • 105
    • 106
    • 107
    • 108
    • 109
    • 110
    • 111
    • 112
    • 113
    • 114
    • 115
    • 116
    • 117
    • 118
    • 119
    • 120
    • 121
    • 122
    • 123
    • 124
    • 125
    • 126
    • 127
    • 128
    • 129
    • 130
    • 131
    • 132
    • 133
    • 134
    • 135
    • 136
    • 137
    • 138
    • 139
    • 140
    • 141
    • 142
    • 143
    • 144
    • 145
    • 146
    • 147
    • 148
    • 149
    • 150
    • 151
    • 152
    • 153
    • 154
    • 155
    • 156
    • 157
    • 158
    • 159
    • 160
    • 161
    • 162
    • 163
    • 164
    • 165
    • 166
    • 167
    • 168
    • 169
    • 170
    • 171
    • 172
    • 173
    • 174
    • 175
    • 176
    • 177
    • 178
    • 179
    • 180
    • 181
    • 182
    • 183
    • 184
    • 185
    • 186
    • 187
    • 188
    • 189
    • 190
    • 191
    • 192
    • 193
    • 194
    • 195
    • 196
    • 197
    • 198
    • 199
    • 200
    • 201
    • 202
    • 203
    • 204
    • 205
    • 206
    • 207
    • 208
    • 209
    • 210
    • 211
    • 212
    • 213
    • 214
    • 215
    • 216
    • 217
    • 218
    • 219
    • 220
    • 221
    • 222
    • 223
    • 224
    • 225
    • 226
    • 227
    • 228
    • 229
    • 230
    • 231
    • 232
    • 233
    • 234
    • 235
    • 236
    • 237
    • 238
    • 239
    • 240
    • 241
    • 242
    • 243
    • 244
    • 245
    • 246
    • 247
    • 248
    • 249
    • 250
    • 251
    • 252
    • 253
    • 254
    • 255
    • 256
    • 257
    • 258
    • 259
    • 260
    • 261
    • 262
    • 263
    • 264
    • 265
    • 266
    • 267
    • 268
    • 269
    • 270
    • 271
    • 272
    • 273
    • 274
    • 275
    • 276
    • 277
    • 278
    • 279
    • 280
    • 281
    • 282
    • 283
    • 284
    • 285
    • 286
    • 287
    • 288
    • 289
    • 290
    • 291
    • 292
    • 293
    • 294
    • 295
    • 296
    • 297
    • 298
    • 299
    • 300
    • 301
    • 302
    • 303
    • 304
    • 305
    • 306
    • 307
    • 308
    • 309
    • 310
    • 311
    • 312
    • 313
    • 314
    • 315
    • 316
    • 317
    • 318
    • 319
    • 320
    • 321
    • 322
    • 323
    • 324
    • 325
    • 326
    • 327
    • 328
    • 329
    • 330
    • 331
    • 332
    • 333
    • 334
    • 335
    • 336
    • 337
    • 338
    • 339
    • 340
    • 341
    • 342
    • 343
    • 344

    STC的这部分代码同样存在一个显示小bug,由于深圳天气种类较少,我便偷懒将接收串口的数据固定为某个长度的数组,显示也是固定某个长度,如果换做其他地区的话可能天气种类较多,出现显示不全等情况,只是个小问题,各位可以稍加修改。

    TFT显示函数

    刷屏函数

    /*************************************************
    函数名:renovateTFT
    功能:用颜色刷新显示屏
    入口参数:int color 颜色选择
    返回值:无
    *************************************************/
    void renovateTFT(int color)
    {
     	unsigned char i,j;
    	setTFTRegion(0, 0, 128-1, 128-1);
     	for (i = 0; i < 128; i ++)
        	for (j = 0;j < 128; j ++)
            	writeTFTData16(color);
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14

    显示文本函数

    /*************************************************
    函数名:displayASCII8X16
    功能:显示ASCII码,大小为8*16像素
    入口参数:	unsigned int x0,				放置坐标x 
    			unsigned int y0, 				放置坐标y
    			unsigned char *s, 				显示的字符串
    			unsigned int forecolor, 		前景颜色
    			unsigned int backgroundcolor	背景颜色
    返回值:无
    *************************************************/
    void displayASCII8X16(unsigned int x0, unsigned int y0, unsigned char *s, unsigned int size, unsigned int forecolor, unsigned int backgroundcolor)
    {
    	int i,j,x,y,xx;
    	
    	long int ulOffset;
    	
    	char  xdata ywbuf[32];
    	
    	for(i = 0; i< size; i++)
    	{
    		if(s[i] >= 161)
    			return;
    		else
    		{
    			ulOffset = (long int)s[i] * 16;
    			for (j = 0; j < 16; j ++)
    			{
    				ywbuf[j] = Zk_ASCII8X16[ulOffset+j];
    			}
    			
    			for(y = 0; y < 16; y++)
    			{
    				for(x = 0; x < 8; x++) 
    				{
    					if(ywbuf[y] & (0x80 >> x))
    					{
    						xx = x0 + x + i * 8;
    						putPixel(xx, y + y0, forecolor);
    					}
    					else
    					{
    						xx=x0 + x + i * 8;
    						putPixel(xx, y + y0, backgroundcolor);	
    					}
    				}
    			}
    		
    		}
    	}     	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    • 45
    • 46
    • 47
    • 48
    • 49
    • 50

    背景图片函数,需要先用Img2Lcd将图片取模(注意图片大小,一般取得数组几千元素,需要加code存放到ROM中)

    void showimage(const unsigned char *p) //显示40*40 
    {
      	int i,j,k; 
    	unsigned char picH,picL;
    	dsp_single_colour(WHITE); //清屏  
    	
    	for(k=0;k<3;k++)
    	{
    	   	for(j=0;j<3;j++)
    		{	
    			setTFTRegion(45*j,45*k,45*j+39,45*k+39);		//坐标设置
    		    for(i=0;i<45*45;i++)
    			 {	
    			 	picL=*(p+i*2);	//数据低位在前
    				picH=*(p+i*2+1);				
    				writeTFTData16(picH<<8|picL);  						
    			 }	
    		 }
    	}		
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    六、结果展示

    注意:此处两条线连接电脑仅仅是为了供电,在下载烧录的时候一定要断开一个,否则会串口冲突,烧录失败,如果各位无法成功测试,欢迎评论区留言或者私信。
    在这里插入图片描述
    在这里插入图片描述
    感悟:
    这是我见过作业最多的一门课了,三学分的课比两门五学分课程加起来的作业还要多的多,这也是我学到东西最多的一门课,51汇编、Proteus、内存关系、数码管的各种操作、按键细节操作、中断、串口、AD转换、DS18B20、LCD1602、LCD12864、TFT、ESP8266NodeMCU、API等等等等,虽然一周三份代码+实验+选择填空(找不到答案的那种)真的很伤头发哈哈哈,但是真的真的非常非常感谢这位老师。

    非常感谢各位的观看,总有一天,您会看见我长成参天大树的。

    系列文章——STC8H8K汇编51实战

    STC8H8K系列汇编和C51实战——实现跑马灯(51版)

    STC8H8K系列汇编和C51实战——实现跑马灯(汇编版)

    STC8H8K系列汇编和C51实战——实现键控不同方式数码管动态显示(C51版与汇编版)

    STC8H8K系列汇编和C51实战——开关控制定时器秒表(C51版)

    STC8H8K系列汇编和C51实战——开关控制定时器秒表(汇编版)

    STC8H8K系列汇编和C51实战——双中断控制定时器流水灯

    STC8H8K系列汇编和C51实战——双中断加减计数器

    STC8H8K系列汇编和C51实战——简易频率计

    STC8H8K系列汇编和C51实战——秒倒计时器(汇编版)

    STC8H8K系列汇编和C51实战——秒倒计时器(51版)

    STC8H8K系列汇编和C51实战——秒倒计时器(可自行设定初值)(51版)

    STC8H8K系列汇编和C51实战——按键允许按键计数(51版)

    STC8H8K系列汇编和C51实战——按键允许按键计数(汇编版)

    STC8H8K系列汇编和C51实战——按键允许按键计数(定时器去抖动51版)

    STC8H8K系列汇编和C51实战——按键允许按键计数(利用下降沿中断控制)

    STC8H8K系列汇编和C51实战——计算机串口控制单片机LED

    STC8H8K系列汇编和C51实战——串口发送菜单界面选择不同功能

    STC8H8K系列汇编和C51实战——数码管显示ADC、串口显示ADC按键与数值

  • 相关阅读:
    D. Number into Sequence【1300】
    react+antd封装表格组件2.0
    用java实现客服聊天+网络爬虫下载音乐(java网络编程,io,多线程)
    Linux:冯诺依曼系统和操作系统的概念
    hypermesh常用快捷键
    阿里巴巴面试题- - -多线程&并发篇(三十五)
    精简版STC单片机串口程序(只有初始化和sendbyte)
    SpringCloud Alibaba - 分布式事务理论(CAP 定理 和 BASE 理论)
    【c#】前后端分离练习小项目学习笔记----纯干货
    GPT与人类共生:解析AI助手的兴起
  • 原文地址:https://blog.csdn.net/qq_56225568/article/details/125437529