DHT11驱动代码_1

Tutorial: 电子电路 Category: 嵌入式 Published: 2026-10-08 01:26:37 Views: 1 Likes: 0 Comments: 0

071.9.10 IIC总结

/* ==================== main.c:把 OLED 显示层接入独立 I²C 模块 ====================
 * 迁移要点:OLED 模块不再直接操作 P1.4/P1.5,而是调用 IIC_Start、IIC_Send_Byte、IIC_Recv_Ack、IIC_Stop。
 * 这样显示函数保持不变时,可单独替换/调试底层总线驱动。
 */
#include "reg52.h" /* 引入 8051 寄存器定义。 */
#include <intrins.h>
#include "delay.h"
#include "main.h"
#include "uart.h"
#include "oled.h"  /* 引入 OLED 初始化和显示接口。 */

uchar recv;

void main()
{
//	UART_Init();
	OLED_Init();      /* 配置 SSD1306,并经 IIC 模块将命令发送到 OLED。 */
	OLED_Clear();     /* 清空显示 RAM,建立确定的起始画面。 */

	OLED_ShowCHinese(0+10,0,0);  /* 第 0 个 16×16 汉字从第 0 页、x=10 开始显示。 */
	OLED_ShowCHinese(18+10,0,1); /* 后续字符横向错开 18 列,索引决定从 Hzk 取哪组字模。 */
	OLED_ShowCHinese(36+10,0,2);
	OLED_ShowCHinese(54+10,0,3);
	OLED_ShowCHinese(72+10,0,4);
	OLED_ShowCHinese(90+10,0,5);

OLED_ShowCHinese(18+10,2,6); /* y=2 表示从第 2 页(第 16 行)开始绘制第二行汉字。 */
	OLED_ShowCHinese(36+10,2,7);
	OLED_ShowCHinese(54+10,2,8);
	OLED_ShowCHinese(72+10,2,9);


	while(1)
  {
		//OLED_Clear();
    //OLED_ShowString(6,3,"I am wfeng",16);
		OLED_ShowString(0,6,"STUDY:",12);  /* 在底部第 6 页显示 6×8 ASCII 字符串。 */
		OLED_ShowString(63,6,"LERN:",12);  /* 原样保留课程示例中的 “LERN:” 拼写。 */
		OLED_ShowChar(48,6,'A',16);        /* 单独测试 8×16 字符字模的上下两页写入。 */
		
		OLED_ShowNum(103,6,6,3,16);        /* 以 3 位 16 像素字体显示数字 6,前导空位由函数补空格。 */
		Delay_xms(1000);                   /* 示例画面不改变;此延时只降低循环频率。 */
  }
}


/* ==================== main.h ==================== */
#ifndef _MAIN_H_
#define _MAIN_H_

#include "reg52.h" /* 8051 端口及特殊功能寄存器定义。 */

typedef unsigned char uchar; /* 课程代码中的 8 位无符号类型别名。 */
typedef unsigned int uint;   /* Keil C51 中通常为 16 位无符号整数。 */

extern uchar recv;

sbit LED1 = P1^0;
sbit LED2 = P1^1;
sbit LED3 = P1^2;
sbit LED4 = P1^3;
sbit BEEP = P1^6;
sbit JDQ1 = P2^0;

sbit IIC_SCL = P1^5; /* 软件 I²C 时钟线;与 OLED 的 SCL 相连。 */
sbit IIC_SDA = P1^4; /* 软件 I²C 数据线;与 OLED 的 SDA 相连。 */

#endif

/* ==================== Delay\delay.c ==================== */
#include "delay.h"
#include <intrins.h>

void Delay_xms(uint xms)	/* 以 11.0592 MHz 为前提的粗略毫秒延时。 */
{
	uchar data i, j;
	while(xms)              /* 每轮消耗约 1 ms,直到请求次数归零。 */
	{
		_nop_();
		i = 2;
		j = 199;
		do
		{
			while (--j);
		} while (--i);
    xms--;		        /* 已完成一个毫秒时间片。 */
	}
}

void Delay5us(void)	//@11.0592MHz
{
}

/* ==================== Delay\delay.h ==================== */
#ifndef _DELAY_H_
#define _DELAY_H_
#include "main.h"

void Delay_xms(uint xms);
void Delay5us(void);

#endif

/* ==================== IIC\iic.c ==================== */
#include "iic.h"
#include "main.h"
#include "delay.h"

void IIC_Start(void) /* I²C 起始条件:SCL 为高电平期间,SDA 由高变低。 */
{
	IIC_SCL = 1; /* 先释放时钟线。 */
	IIC_SDA = 1; /* 空闲总线的两根线均为高。 */
	Delay5us();  /* 保证起始条件的建立时间。 */
	IIC_SDA = 0; /* SCL 高电平时拉低 SDA,形成 START。 */
	Delay5us();
	IIC_SCL = 0; /* 后续数据位在 SCL 低电平阶段准备。 */
}

void IIC_Stop(void) /* I²C 停止条件:SCL 为高电平期间,SDA 由低变高。 */
{
	IIC_SCL = 1; /* 先把时钟恢复为高。 */
	IIC_SDA = 0; /* 确保数据线从低电平开始变化。 */
	Delay5us();
	IIC_SDA = 1; /* SCL 高电平时释放 SDA,形成 STOP。 */
}

void IIC_Send_Byte(unsigned char IIC_Byte) /* 按最高位优先发送 8 个数据位。 */
{
	char i;
	for(i = 0; i<8; i++)
	{		
		IIC_SDA = IIC_Byte & (0x80 >> i); /* 依次取 bit7 到 bit0;非零值会驱动为高。 */
		IIC_SCL = 1;                      /* 上升沿/高电平阶段让从机采样该位。 */
		Delay5us();
		IIC_SCL = 0;                      /* 回到低电平,准备下一位。 */
		Delay5us();		
	}
}

unsigned char IIC_Recv_Ack(void) /* 读取第 9 个时钟周期的 ACK:0 为应答,1 为未应答。 */
{
	unsigned char ack;
	IIC_SDA = 1; /* 释放 SDA,让从机能够驱动应答位。 */
	IIC_SCL = 1; /* 第 9 个时钟高电平。 */
	Delay5us();
	ack = IIC_SDA; /* 采样从机给出的 ACK/NACK 电平。 */
	IIC_SCL = 0;
	Delay5us();	
	
	return ack;
}

/* ==================== IIC\iic.h ==================== */
#ifndef _IIC_H_
#define _IIC_H_

void IIC_Start(void);
void IIC_Stop(void);
void IIC_Send_Byte(unsigned char IIC_Byte);
unsigned char IIC_Recv_Ack(void);

#endif

/* ==================== OLED\oled.c:显示层,通过 iic.h 使用总线接口 ==================== */
#include "oled.h"
#include "oledfont.h"  	 
#include "iic.h"   /* 引入独立 I²C 模块的 START、发送、ACK 读取和 STOP 接口。 */

//OLED的显存
//存放格式如下.
//[0]0 1 2 3 ... 127	
//[1]0 1 2 3 ... 127	
//[2]0 1 2 3 ... 127	
//[3]0 1 2 3 ... 127	
//[4]0 1 2 3 ... 127	
//[5]0 1 2 3 ... 127	
//[6]0 1 2 3 ... 127	
//[7]0 1 2 3 ... 127 			   
void delay_ms(unsigned int ms)
{                         
	unsigned int a;
	while(ms)
	{
		a=1800;
		while(a--);
		ms--;
	}
	return;
}
/**********************************************
//I²C 起始信号
**********************************************/
//void IIC_Start()
//{
//	OLED_SCLK_Set() ;
//	OLED_SDIN_Set();
//	OLED_SDIN_Clr();
//	OLED_SCLK_Clr();
//}

/**********************************************
//I²C 停止信号
**********************************************/
//void IIC_Stop()
//{
//  OLED_SCLK_Set() ;
//  //OLED_SCLK_Clr();
//	OLED_SDIN_Clr();
//	OLED_SDIN_Set();
//	
//}

//void IIC_Wait_Ack()
//{
//	OLED_SCLK_Set() ;
//	OLED_SCLK_Clr();
//}
/**********************************************
// I²C 写入一个字节
**********************************************/

//void Write_IIC_Byte(unsigned char IIC_Byte)
//{
//	unsigned char i;
//	unsigned char m,da;
//	da=IIC_Byte;
//	OLED_SCLK_Clr();
//	for(i=0;i<8;i++)		
//	{
//		m=da;
//		//	OLED_SCLK_Clr();
//		m=m&0x80;
//		if(m==0x80)
//		{OLED_SDIN_Set();}
//		else OLED_SDIN_Clr();
//			da=da<<1;
//		OLED_SCLK_Set();
//		OLED_SCLK_Clr();
//	}
//}
/**********************************************
// I²C 写命令
**********************************************/
void Write_IIC_Command(unsigned char IIC_Command) /* 写一个 SSD1306 命令帧;所有物理时序由 IIC 模块完成。 */
{
	IIC_Start();              /* 产生 START,占用 I²C 总线。 */
	IIC_Send_Byte(0x78);      /* SSD1306 地址 0x3C 加写方向位。 */
	IIC_Recv_Ack();           /* 读取应答;原例程未根据返回值处理 NACK,这是后续可完善的错误路径。 */
	IIC_Send_Byte(0x00);      /* 控制字节:后续载荷按命令解释。 */
	IIC_Recv_Ack();           /* 检查控制字节应答。 */
	IIC_Send_Byte(IIC_Command); /* 发送调用者指定的 SSD1306 命令。 */
	IIC_Recv_Ack();           /* 检查命令字节应答。 */
	IIC_Stop();               /* 产生 STOP,释放总线。 */
}
/**********************************************
// I²C 写数据
**********************************************/
void Write_IIC_Data(unsigned char IIC_Data) /* 写一个显示 RAM 数据帧。 */
{
	IIC_Start();              /* 开始本次数据事务。 */
	IIC_Send_Byte(0x78);      /* 选择 SSD1306 并写入。 */
	IIC_Recv_Ack();           /* 读取地址应答。 */
	IIC_Send_Byte(0x40);      /* 控制字节:后续载荷写入 GDDRAM。 */
	IIC_Recv_Ack();           /* 读取控制字节应答。 */
	IIC_Send_Byte(IIC_Data);  /* 写当前页/列指针指向的 8 个纵向像素。 */
	IIC_Recv_Ack();           /* 读取数据应答。 */
	IIC_Stop();               /* 完成本次单字节写入。 */
}

void OLED_WR_Byte(unsigned dat,unsigned cmd) /* 根据 cmd 将一个字节分流为命令或显示数据。 */
{
	if(cmd) /* OLED_DATA 为 1,走数据帧;OLED_CMD 为 0,走命令帧。 */
	{
    Write_IIC_Data(dat);  /* 数据字节会写入当前 GDDRAM 地址。 */
	}
	else
	{
    Write_IIC_Command(dat); /* 命令字节用于配置地址、显示状态等。 */
	}
}

/********************************************
// 填充整屏图像
********************************************/
void fill_picture(unsigned char fill_Data) /* 用同一字节填满 8 页 × 128 列的整块显示 RAM。 */
{
	unsigned char m,n;
	for(m=0;m<8;m++) /* SSD1306 的 64 行屏幕分为 8 个页。 */
	{
		OLED_WR_Byte(0xb0+m,0);		//设置当前页地址
		OLED_WR_Byte(0x00,0);		//设置列地址低四位
		OLED_WR_Byte(0x10,0);		//设置列地址高四位
		for(n=0;n<128;n++)
		{
			OLED_WR_Byte(fill_Data,1); /* 每个字节控制当前列连续的 8 个纵向像素。 */
		}
	}
}


/***********************延时函数****************************************/
void Delay_50ms(unsigned int Del_50ms)
{
	unsigned int m;
	for(;Del_50ms>0;Del_50ms--)
		for(m=6245;m>0;m--);
}

void Delay_1ms(unsigned int Del_1ms)
{
	unsigned char j;
	while(Del_1ms--)
	{	
		for(j=0;j<123;j++);
	}
}

//坐标设置
void OLED_Set_Pos(unsigned char x, unsigned char y) /* 将后续数据写入定位到列 x、页 y。 */
{ 
	OLED_WR_Byte(0xb0+y,OLED_CMD);              /* 选择 0~7 页。 */
	OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD); /* 写列地址高 4 位。 */
	OLED_WR_Byte((x&0x0f),OLED_CMD);           /* 写列地址低 4 位。 */
}   	  
//开启OLED显示    
void OLED_Display_On(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X14,OLED_CMD);  //开启内部升压电路
	OLED_WR_Byte(0XAF,OLED_CMD);  //开启显示
}
//关闭OLED显示     
void OLED_Display_Off(void)
{
	OLED_WR_Byte(0X8D,OLED_CMD);  //SET DCDC命令
	OLED_WR_Byte(0X10,OLED_CMD);  //关闭内部升压电路
	OLED_WR_Byte(0XAE,OLED_CMD);  //关闭显示
}		   			 
//清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!!	  
void OLED_Clear(void)  
{  
	u8 i,n;		    
	for(i=0;i<8;i++)  
	{  
		OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
		OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
		for(n=0;n<128;n++)
		  OLED_WR_Byte(0,OLED_DATA); 
	} //更新显示
}
void OLED_On(void)  
{  
	u8 i,n;		    
	for(i=0;i<8;i++)  
	{  
		OLED_WR_Byte (0xb0+i,OLED_CMD);    //设置页地址(0~7)
		OLED_WR_Byte (0x00,OLED_CMD);      //设置显示位置—列低地址
		OLED_WR_Byte (0x10,OLED_CMD);      //设置显示位置—列高地址   
		for(n=0;n<128;n++)
		 OLED_WR_Byte(1,OLED_DATA); 
	} //更新显示
}
//在指定位置显示一个字符,包括部分字符
//x:0~127
//y:0~63
//mode:0,反白显示;1,正常显示				 
//size:选择字体 16/12 
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size) /* 从字模表取出一个 ASCII 字符并写到屏幕。 */
{      	
	unsigned char c=0,i=0;	
	c=chr-' '; /* 字模表从空格(ASCII 0x20)开始存储,因此先换算下标。 */
	if(x>Max_Column-1)
	{
		x=0;   /* 超出右边界则回到行首。 */
		y=y+2; /* 16 像素字高占两页,换行时页号加 2。 */
	}
	if(Char_Size ==16)
	{
		OLED_Set_Pos(x,y); /* 先写字模上半部分所在页。 */
		for(i=0;i<8;i++)
		OLED_WR_Byte(F8X16[c*16+i],OLED_DATA);
		OLED_Set_Pos(x,y+1); /* 再写字模下半部分到下一页。 */
		for(i=0;i<8;i++)
		OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA);
	}
	else 
	{	
		OLED_Set_Pos(x,y); /* 6×8 字符只占一个页。 */
		for(i=0;i<6;i++)
		OLED_WR_Byte(F6x8[c][i],OLED_DATA);			
	}
}
//m^n函数
u32 oled_pow(u8 m,u8 n) /* 整数幂:供十进制拆位使用。 */
{
	u32 result=1;	 
	while(n--)
	{
	  result*=m; /* 每循环一次多乘一个底数。 */
	}    
	return result;
}				  
//显示2个数字
//x,y :起点坐标	 
//len :数字的位数
//size:字体大小
//mode:模式	0,填充模式;1,叠加模式
//num:数值(0~4294967295);	 		  
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size2) /* 按固定宽度显示无符号十进制数。 */
{         	
	u8 t,temp;
	u8 enshow=0;						   
	for(t=0;t<len;t++)
	{
		temp=(num/oled_pow(10,len-t-1))%10; /* 用除法和取模取出当前位置的十进制数字。 */
		if(enshow==0&&t<(len-1))
		{
			if(temp==0)
			{
				OLED_ShowChar(x+(size2/2)*t,y,' ',size2); /* 隐藏前导零,保持字段对齐。 */
				continue;
			}
			else 
				enshow=1; 		 	 
		}
	 	OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2); /* 将 0~9 转为对应 ASCII 码再显示。 */
	}
} 
//显示一个字符号串
void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 Char_Size) /* 逐字符显示以 '\\0' 结尾的字符串。 */
{
	unsigned char j=0;
	while (chr[j]!='\0')
	{		
		OLED_ShowChar(x,y,chr[j],Char_Size); /* 显示当前字符。 */
		x+=8;                                /* 示例按 8 列步进,适用于 8×16 字体。 */
		if(x>120){x=0;y+=2;}                 /* 即将越界时换到下一字符行。 */
		 j++;
	}
}
//显示汉字
void OLED_ShowCHinese(u8 x,u8 y,u8 no) /* 将第 no 个 16×16 汉字的两组 16 字节字模写入两页。 */
{      			    
	u8 t,adder=0;
	OLED_Set_Pos(x,y); /* 写上半部分。 */
	for(t=0;t<16;t++)
	{
		OLED_WR_Byte(Hzk[2*no][t],OLED_DATA); /* Hzk 每个汉字占两行数组,偶数行是上半部分。 */
		adder+=1;
	}	
	OLED_Set_Pos(x,y+1); /* 写下半部分。 */
	for(t=0;t<16;t++)
	{	
		OLED_WR_Byte(Hzk[2*no+1][t],OLED_DATA); /* 奇数行对应同一汉字的下半部分。 */
		adder+=1;
	}					
}
/***********功能描述:显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7*****************/
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[]) /* 依页写入一幅位图。 */
{ 	
 unsigned int j=0;
 unsigned char x,y;
  
  if(y1%8==0)
		y=y1/8;      
  else 
		y=y1/8+1;
	for(y=y0;y<y1;y++)
	{
		OLED_Set_Pos(x0,y);
    for(x=x0;x<x1;x++)
	  {      
	    OLED_WR_Byte(BMP[j++],OLED_DATA); /* 位图数据按页、按列连续消费。 */
	  }
	}
} 

//初始化SSD1306					    
void OLED_Init(void) /* 依 SSD1306 初始化顺序配置寻址、扫描方向、供电与显示开关。 */
{ 	
 
	OLED_WR_Byte(0xAE,OLED_CMD);//关闭显示
	OLED_WR_Byte(0x00,OLED_CMD);//设置列地址低四位
	OLED_WR_Byte(0x10,OLED_CMD);//设置列地址高四位
	OLED_WR_Byte(0x40,OLED_CMD);//设置显示起始行  
	OLED_WR_Byte(0xB0,OLED_CMD);//设置页地址
	OLED_WR_Byte(0x81,OLED_CMD); //设置对比度
	OLED_WR_Byte(0xFF,OLED_CMD);//--128   
	OLED_WR_Byte(0xA1,OLED_CMD);//设置段重映射 
	OLED_WR_Byte(0xA6,OLED_CMD);//设置正常显示而非反色显示
	OLED_WR_Byte(0xA8,OLED_CMD);//设置多路复用比(1~64)
	OLED_WR_Byte(0x3F,OLED_CMD);//设置显示占空比
	OLED_WR_Byte(0xC8,OLED_CMD);//设置 COM 扫描方向
	OLED_WR_Byte(0xD3,OLED_CMD);//设置显示偏移
	OLED_WR_Byte(0x00,OLED_CMD);//
	
	OLED_WR_Byte(0xD5,OLED_CMD);//设置振荡器分频
	OLED_WR_Byte(0x80,OLED_CMD);//
	
	OLED_WR_Byte(0xD8,OLED_CMD);//关闭区域彩色模式
	OLED_WR_Byte(0x05,OLED_CMD);//
	
	OLED_WR_Byte(0xD9,OLED_CMD);//设置预充电周期
	OLED_WR_Byte(0xF1,OLED_CMD);//
	
	OLED_WR_Byte(0xDA,OLED_CMD);//设置 COM 引脚硬件配置
	OLED_WR_Byte(0x12,OLED_CMD);//
	
	OLED_WR_Byte(0xDB,OLED_CMD);//设置 VCOMH 电平
	OLED_WR_Byte(0x30,OLED_CMD);//
	
	OLED_WR_Byte(0x8D,OLED_CMD);//配置电荷泵
	OLED_WR_Byte(0x14,OLED_CMD);//
	
	OLED_WR_Byte(0xAF,OLED_CMD);//开启 OLED 面板显示
}  

/* ==================== OLED\oled.h ==================== */
//#include "REG51.h"
#ifndef __OLED_H
#define __OLED_H			  	 
//#include "sys.h"
//#include "stdlib.h"	  
#define  u8 unsigned char 
#define  u32 unsigned int 
#define OLED_CMD  0	/* OLED_WR_Byte 的命令通道标记。 */
#define OLED_DATA 1	/* OLED_WR_Byte 的显示数据通道标记。 */
#define OLED_MODE 0

//sbit OLED_SCL=P1^5;//时钟 D0(SCLK?
//sbit OLED_SDIN=P1^4;//D1(MOSI) 数据

//#define OLED_SCLK_Clr() OLED_SCL=0
//#define OLED_SCLK_Set() OLED_SCL=1

//#define OLED_SDIN_Clr() OLED_SDIN=0
//#define OLED_SDIN_Set() OLED_SDIN=1

//OLED模式设置
//0:4线串行模式
//1:并行8080模式

#define SIZE 16
#define XLevelL		0x02
#define XLevelH		0x10
#define Max_Column	128
#define Max_Row		64
#define	Brightness	0xFF 
#define X_WIDTH 	128
#define Y_WIDTH 	64	    						  
//-----------------OLED端口定义----------------  					   

void delay_ms(unsigned int ms);

//OLED控制用函数
void OLED_WR_Byte(unsigned dat,unsigned cmd);  
void OLED_Display_On(void);
void OLED_Display_Off(void);	   							   		    
void OLED_Init(void);
void OLED_Clear(void);
void OLED_DrawPoint(u8 x,u8 y,u8 t);
void OLED_Fill(u8 x1,u8 y1,u8 x2,u8 y2,u8 dot);
void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 Char_Size);
void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 size);
void OLED_ShowString(u8 x,u8 y, u8 *p,u8 Char_Size);	 
void OLED_Set_Pos(unsigned char x, unsigned char y);
void OLED_ShowCHinese(u8 x,u8 y,u8 no);
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[]);
void Delay_50ms(unsigned int Del_50ms);
void Delay_1ms(unsigned int Del_1ms);
void fill_picture(unsigned char fill_Data);
void Picture();
void IIC_Start();
void IIC_Stop();
void Write_IIC_Command(unsigned char IIC_Command);
void Write_IIC_Data(unsigned char IIC_Data);
void Write_IIC_Byte(unsigned char IIC_Byte);
void IIC_Wait_Ack();

#endif

/* ==================== OLED\oledfont.h ==================== */
#ifndef __OLEDFONT_H
#define __OLEDFONT_H 	   
//常用ASCII表
//偏移量32
//ASCII字符集
//偏移量32
//大小:12*6
/************************************6*8的点阵************************************/
/* 字模/位图为取模工具生成的资源数据;字节位即像素状态,保留整体说明和字符标签,无需逐字节添加无意义注释。 */
const unsigned char code F6x8[][6] =		
{
0x00, 0x00, 0x00, 0x00, 0x00, 0x00,// 空格字符
0x00, 0x00, 0x00, 0x2f, 0x00, 0x00,// !
0x00, 0x00, 0x07, 0x00, 0x07, 0x00,// "
0x00, 0x14, 0x7f, 0x14, 0x7f, 0x14,// #
0x00, 0x24, 0x2a, 0x7f, 0x2a, 0x12,// $
0x00, 0x62, 0x64, 0x08, 0x13, 0x23,// %
0x00, 0x36, 0x49, 0x55, 0x22, 0x50,// &
0x00, 0x00, 0x05, 0x03, 0x00, 0x00,// '
0x00, 0x00, 0x1c, 0x22, 0x41, 0x00,// (
0x00, 0x00, 0x41, 0x22, 0x1c, 0x00,// )
0x00, 0x14, 0x08, 0x3E, 0x08, 0x14,// *
0x00, 0x08, 0x08, 0x3E, 0x08, 0x08,// +
0x00, 0x00, 0x00, 0xA0, 0x60, 0x00,// ,
0x00, 0x08, 0x08, 0x08, 0x08, 0x08,// -
0x00, 0x00, 0x60, 0x60, 0x00, 0x00,// .
0x00, 0x20, 0x10, 0x08, 0x04, 0x02,// /
0x00, 0x3E, 0x51, 0x49, 0x45, 0x3E,// 0
0x00, 0x00, 0x42, 0x7F, 0x40, 0x00,// 1
0x00, 0x42, 0x61, 0x51, 0x49, 0x46,// 2
0x00, 0x21, 0x41, 0x45, 0x4B, 0x31,// 3
0x00, 0x18, 0x14, 0x12, 0x7F, 0x10,// 4
0x00, 0x27, 0x45, 0x45, 0x45, 0x39,// 5
0x00, 0x3C, 0x4A, 0x49, 0x49, 0x30,// 6
0x00, 0x01, 0x71, 0x09, 0x05, 0x03,// 7
0x00, 0x36, 0x49, 0x49, 0x49, 0x36,// 8
0x00, 0x06, 0x49, 0x49, 0x29, 0x1E,// 9
0x00, 0x00, 0x36, 0x36, 0x00, 0x00,// :
0x00, 0x00, 0x56, 0x36, 0x00, 0x00,// ;
0x00, 0x08, 0x14, 0x22, 0x41, 0x00,// <
0x00, 0x14, 0x14, 0x14, 0x14, 0x14,// =
0x00, 0x00, 0x41, 0x22, 0x14, 0x08,// >
0x00, 0x02, 0x01, 0x51, 0x09, 0x06,// ?
0x00, 0x32, 0x49, 0x59, 0x51, 0x3E,// @
0x00, 0x7C, 0x12, 0x11, 0x12, 0x7C,// A
0x00, 0x7F, 0x49, 0x49, 0x49, 0x36,// B
0x00, 0x3E, 0x41, 0x41, 0x41, 0x22,// C
0x00, 0x7F, 0x41, 0x41, 0x22, 0x1C,// D
0x00, 0x7F, 0x49, 0x49, 0x49, 0x41,// E
0x00, 0x7F, 0x09, 0x09, 0x09, 0x01,// F
0x00, 0x3E, 0x41, 0x49, 0x49, 0x7A,// G
0x00, 0x7F, 0x08, 0x08, 0x08, 0x7F,// H
0x00, 0x00, 0x41, 0x7F, 0x41, 0x00,// I
0x00, 0x20, 0x40, 0x41, 0x3F, 0x01,// J
0x00, 0x7F, 0x08, 0x14, 0x22, 0x41,// K
0x00, 0x7F, 0x40, 0x40, 0x40, 0x40,// L
0x00, 0x7F, 0x02, 0x0C, 0x02, 0x7F,// M
0x00, 0x7F, 0x04, 0x08, 0x10, 0x7F,// N
0x00, 0x3E, 0x41, 0x41, 0x41, 0x3E,// O
0x00, 0x7F, 0x09, 0x09, 0x09, 0x06,// P
0x00, 0x3E, 0x41, 0x51, 0x21, 0x5E,// Q
0x00, 0x7F, 0x09, 0x19, 0x29, 0x46,// R
0x00, 0x46, 0x49, 0x49, 0x49, 0x31,// S
0x00, 0x01, 0x01, 0x7F, 0x01, 0x01,// T
0x00, 0x3F, 0x40, 0x40, 0x40, 0x3F,// U
0x00, 0x1F, 0x20, 0x40, 0x20, 0x1F,// V
0x00, 0x3F, 0x40, 0x38, 0x40, 0x3F,// W
0x00, 0x63, 0x14, 0x08, 0x14, 0x63,// X
0x00, 0x07, 0x08, 0x70, 0x08, 0x07,// Y
0x00, 0x61, 0x51, 0x49, 0x45, 0x43,// Z
0x00, 0x00, 0x7F, 0x41, 0x41, 0x00,// [
0x00, 0x55, 0x2A, 0x55, 0x2A, 0x55,// 55
0x00, 0x00, 0x41, 0x41, 0x7F, 0x00,// ]
0x00, 0x04, 0x02, 0x01, 0x02, 0x04,// ^
0x00, 0x40, 0x40, 0x40, 0x40, 0x40,// _
0x00, 0x00, 0x01, 0x02, 0x04, 0x00,// '
0x00, 0x20, 0x54, 0x54, 0x54, 0x78,// a
0x00, 0x7F, 0x48, 0x44, 0x44, 0x38,// b
0x00, 0x38, 0x44, 0x44, 0x44, 0x20,// c
0x00, 0x38, 0x44, 0x44, 0x48, 0x7F,// d
0x00, 0x38, 0x54, 0x54, 0x54, 0x18,// e
0x00, 0x08, 0x7E, 0x09, 0x01, 0x02,// f
0x00, 0x18, 0xA4, 0xA4, 0xA4, 0x7C,// g
0x00, 0x7F, 0x08, 0x04, 0x04, 0x78,// h
0x00, 0x00, 0x44, 0x7D, 0x40, 0x00,// i
0x00, 0x40, 0x80, 0x84, 0x7D, 0x00,// j
0x00, 0x7F, 0x10, 0x28, 0x44, 0x00,// k
0x00, 0x00, 0x41, 0x7F, 0x40, 0x00,// l
0x00, 0x7C, 0x04, 0x18, 0x04, 0x78,// m
0x00, 0x7C, 0x08, 0x04, 0x04, 0x78,// n
0x00, 0x38, 0x44, 0x44, 0x44, 0x38,// o
0x00, 0xFC, 0x24, 0x24, 0x24, 0x18,// p
0x00, 0x18, 0x24, 0x24, 0x18, 0xFC,// q
0x00, 0x7C, 0x08, 0x04, 0x04, 0x08,// r
0x00, 0x48, 0x54, 0x54, 0x54, 0x20,// s
0x00, 0x04, 0x3F, 0x44, 0x40, 0x20,// t
0x00, 0x3C, 0x40, 0x40, 0x20, 0x7C,// u
0x00, 0x1C, 0x20, 0x40, 0x20, 0x1C,// v
0x00, 0x3C, 0x40, 0x30, 0x40, 0x3C,// w
0x00, 0x44, 0x28, 0x10, 0x28, 0x44,// x
0x00, 0x1C, 0xA0, 0xA0, 0xA0, 0x7C,// y
0x00, 0x44, 0x64, 0x54, 0x4C, 0x44,// z
0x14, 0x14, 0x14, 0x14, 0x14, 0x14,// 水平线字符
};
/****************************************8*16的点阵************************************/
const unsigned char code F8X16[]=	  
{
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,// 0
  0x00,0x00,0x00,0xF8,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x33,0x30,0x00,0x00,0x00,//! 1
  0x00,0x10,0x0C,0x06,0x10,0x0C,0x06,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//" 2
  0x40,0xC0,0x78,0x40,0xC0,0x78,0x40,0x00,0x04,0x3F,0x04,0x04,0x3F,0x04,0x04,0x00,//# 3
  0x00,0x70,0x88,0xFC,0x08,0x30,0x00,0x00,0x00,0x18,0x20,0xFF,0x21,0x1E,0x00,0x00,//$ 4
  0xF0,0x08,0xF0,0x00,0xE0,0x18,0x00,0x00,0x00,0x21,0x1C,0x03,0x1E,0x21,0x1E,0x00,//% 5
  0x00,0xF0,0x08,0x88,0x70,0x00,0x00,0x00,0x1E,0x21,0x23,0x24,0x19,0x27,0x21,0x10,//& 6
  0x10,0x16,0x0E,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//' 7
  0x00,0x00,0x00,0xE0,0x18,0x04,0x02,0x00,0x00,0x00,0x00,0x07,0x18,0x20,0x40,0x00,//( 8
  0x00,0x02,0x04,0x18,0xE0,0x00,0x00,0x00,0x00,0x40,0x20,0x18,0x07,0x00,0x00,0x00,//) 9
  0x40,0x40,0x80,0xF0,0x80,0x40,0x40,0x00,0x02,0x02,0x01,0x0F,0x01,0x02,0x02,0x00,//* 10
  0x00,0x00,0x00,0xF0,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x1F,0x01,0x01,0x01,0x00,//+ 11
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0xB0,0x70,0x00,0x00,0x00,0x00,0x00,//, 12
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x01,0x01,0x01,0x01,0x01,0x01,//- 13
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,0x00,0x00,//. 14
  0x00,0x00,0x00,0x00,0x80,0x60,0x18,0x04,0x00,0x60,0x18,0x06,0x01,0x00,0x00,0x00,/// 15
  0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x0F,0x10,0x20,0x20,0x10,0x0F,0x00,//0 16
  0x00,0x10,0x10,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//1 17
  0x00,0x70,0x08,0x08,0x08,0x88,0x70,0x00,0x00,0x30,0x28,0x24,0x22,0x21,0x30,0x00,//2 18
  0x00,0x30,0x08,0x88,0x88,0x48,0x30,0x00,0x00,0x18,0x20,0x20,0x20,0x11,0x0E,0x00,//3 19
  0x00,0x00,0xC0,0x20,0x10,0xF8,0x00,0x00,0x00,0x07,0x04,0x24,0x24,0x3F,0x24,0x00,//4 20
  0x00,0xF8,0x08,0x88,0x88,0x08,0x08,0x00,0x00,0x19,0x21,0x20,0x20,0x11,0x0E,0x00,//5 21
  0x00,0xE0,0x10,0x88,0x88,0x18,0x00,0x00,0x00,0x0F,0x11,0x20,0x20,0x11,0x0E,0x00,//6 22
  0x00,0x38,0x08,0x08,0xC8,0x38,0x08,0x00,0x00,0x00,0x00,0x3F,0x00,0x00,0x00,0x00,//7 23
  0x00,0x70,0x88,0x08,0x08,0x88,0x70,0x00,0x00,0x1C,0x22,0x21,0x21,0x22,0x1C,0x00,//8 24
  0x00,0xE0,0x10,0x08,0x08,0x10,0xE0,0x00,0x00,0x00,0x31,0x22,0x22,0x11,0x0F,0x00,//9 25
  0x00,0x00,0x00,0xC0,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x30,0x30,0x00,0x00,0x00,//: 26
  0x00,0x00,0x00,0x80,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x60,0x00,0x00,0x00,0x00,//; 27
  0x00,0x00,0x80,0x40,0x20,0x10,0x08,0x00,0x00,0x01,0x02,0x04,0x08,0x10,0x20,0x00,//< 28
  0x40,0x40,0x40,0x40,0x40,0x40,0x40,0x00,0x04,0x04,0x04,0x04,0x04,0x04,0x04,0x00,//= 29
  0x00,0x08,0x10,0x20,0x40,0x80,0x00,0x00,0x00,0x20,0x10,0x08,0x04,0x02,0x01,0x00,//> 30
  0x00,0x70,0x48,0x08,0x08,0x08,0xF0,0x00,0x00,0x00,0x00,0x30,0x36,0x01,0x00,0x00,//? 31
  0xC0,0x30,0xC8,0x28,0xE8,0x10,0xE0,0x00,0x07,0x18,0x27,0x24,0x23,0x14,0x0B,0x00,//@ 32
  0x00,0x00,0xC0,0x38,0xE0,0x00,0x00,0x00,0x20,0x3C,0x23,0x02,0x02,0x27,0x38,0x20,//A 33
  0x08,0xF8,0x88,0x88,0x88,0x70,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x11,0x0E,0x00,//B 34
  0xC0,0x30,0x08,0x08,0x08,0x08,0x38,0x00,0x07,0x18,0x20,0x20,0x20,0x10,0x08,0x00,//C 35
  0x08,0xF8,0x08,0x08,0x08,0x10,0xE0,0x00,0x20,0x3F,0x20,0x20,0x20,0x10,0x0F,0x00,//D 36
  0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x20,0x23,0x20,0x18,0x00,//E 37
  0x08,0xF8,0x88,0x88,0xE8,0x08,0x10,0x00,0x20,0x3F,0x20,0x00,0x03,0x00,0x00,0x00,//F 38
  0xC0,0x30,0x08,0x08,0x08,0x38,0x00,0x00,0x07,0x18,0x20,0x20,0x22,0x1E,0x02,0x00,//G 39
  0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x20,0x3F,0x21,0x01,0x01,0x21,0x3F,0x20,//H 40
  0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//I 41
  0x00,0x00,0x08,0x08,0xF8,0x08,0x08,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,0x00,//J 42
  0x08,0xF8,0x88,0xC0,0x28,0x18,0x08,0x00,0x20,0x3F,0x20,0x01,0x26,0x38,0x20,0x00,//K 43
  0x08,0xF8,0x08,0x00,0x00,0x00,0x00,0x00,0x20,0x3F,0x20,0x20,0x20,0x20,0x30,0x00,//L 44
  0x08,0xF8,0xF8,0x00,0xF8,0xF8,0x08,0x00,0x20,0x3F,0x00,0x3F,0x00,0x3F,0x20,0x00,//M 45
  0x08,0xF8,0x30,0xC0,0x00,0x08,0xF8,0x08,0x20,0x3F,0x20,0x00,0x07,0x18,0x3F,0x00,//N 46
  0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x10,0x20,0x20,0x20,0x10,0x0F,0x00,//O 47
  0x08,0xF8,0x08,0x08,0x08,0x08,0xF0,0x00,0x20,0x3F,0x21,0x01,0x01,0x01,0x00,0x00,//P 48
  0xE0,0x10,0x08,0x08,0x08,0x10,0xE0,0x00,0x0F,0x18,0x24,0x24,0x38,0x50,0x4F,0x00,//Q 49
  0x08,0xF8,0x88,0x88,0x88,0x88,0x70,0x00,0x20,0x3F,0x20,0x00,0x03,0x0C,0x30,0x20,//R 50
  0x00,0x70,0x88,0x08,0x08,0x08,0x38,0x00,0x00,0x38,0x20,0x21,0x21,0x22,0x1C,0x00,//S 51
  0x18,0x08,0x08,0xF8,0x08,0x08,0x18,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//T 52
  0x08,0xF8,0x08,0x00,0x00,0x08,0xF8,0x08,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//U 53
  0x08,0x78,0x88,0x00,0x00,0xC8,0x38,0x08,0x00,0x00,0x07,0x38,0x0E,0x01,0x00,0x00,//V 54
  0xF8,0x08,0x00,0xF8,0x00,0x08,0xF8,0x00,0x03,0x3C,0x07,0x00,0x07,0x3C,0x03,0x00,//W 55
  0x08,0x18,0x68,0x80,0x80,0x68,0x18,0x08,0x20,0x30,0x2C,0x03,0x03,0x2C,0x30,0x20,//X 56
  0x08,0x38,0xC8,0x00,0xC8,0x38,0x08,0x00,0x00,0x00,0x20,0x3F,0x20,0x00,0x00,0x00,//Y 57
  0x10,0x08,0x08,0x08,0xC8,0x38,0x08,0x00,0x20,0x38,0x26,0x21,0x20,0x20,0x18,0x00,//Z 58
  0x00,0x00,0x00,0xFE,0x02,0x02,0x02,0x00,0x00,0x00,0x00,0x7F,0x40,0x40,0x40,0x00,//[ 59
  0x00,0x0C,0x30,0xC0,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x01,0x06,0x38,0xC0,0x00,//\ 60
  0x00,0x02,0x02,0x02,0xFE,0x00,0x00,0x00,0x00,0x40,0x40,0x40,0x7F,0x00,0x00,0x00,//] 61
  0x00,0x00,0x04,0x02,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//^ 62
  0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x80,//_ 63
  0x00,0x02,0x02,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//` 64
  0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x19,0x24,0x22,0x22,0x22,0x3F,0x20,//a 65
  0x08,0xF8,0x00,0x80,0x80,0x00,0x00,0x00,0x00,0x3F,0x11,0x20,0x20,0x11,0x0E,0x00,//b 66
  0x00,0x00,0x00,0x80,0x80,0x80,0x00,0x00,0x00,0x0E,0x11,0x20,0x20,0x20,0x11,0x00,//c 67
  0x00,0x00,0x00,0x80,0x80,0x88,0xF8,0x00,0x00,0x0E,0x11,0x20,0x20,0x10,0x3F,0x20,//d 68
  0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x22,0x22,0x22,0x22,0x13,0x00,//e 69
  0x00,0x80,0x80,0xF0,0x88,0x88,0x88,0x18,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//f 70
  0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x6B,0x94,0x94,0x94,0x93,0x60,0x00,//g 71
  0x08,0xF8,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//h 72
  0x00,0x80,0x98,0x98,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//i 73
  0x00,0x00,0x00,0x80,0x98,0x98,0x00,0x00,0x00,0xC0,0x80,0x80,0x80,0x7F,0x00,0x00,//j 74
  0x08,0xF8,0x00,0x00,0x80,0x80,0x80,0x00,0x20,0x3F,0x24,0x02,0x2D,0x30,0x20,0x00,//k 75
  0x00,0x08,0x08,0xF8,0x00,0x00,0x00,0x00,0x00,0x20,0x20,0x3F,0x20,0x20,0x00,0x00,//l 76
  0x80,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x20,0x3F,0x20,0x00,0x3F,0x20,0x00,0x3F,//m 77
  0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x3F,0x21,0x00,0x00,0x20,0x3F,0x20,//n 78
  0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x00,0x1F,0x20,0x20,0x20,0x20,0x1F,0x00,//o 79
  0x80,0x80,0x00,0x80,0x80,0x00,0x00,0x00,0x80,0xFF,0xA1,0x20,0x20,0x11,0x0E,0x00,//p 80
  0x00,0x00,0x00,0x80,0x80,0x80,0x80,0x00,0x00,0x0E,0x11,0x20,0x20,0xA0,0xFF,0x80,//q 81
  0x80,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x20,0x20,0x3F,0x21,0x20,0x00,0x01,0x00,//r 82
  0x00,0x00,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x33,0x24,0x24,0x24,0x24,0x19,0x00,//s 83
  0x00,0x80,0x80,0xE0,0x80,0x80,0x00,0x00,0x00,0x00,0x00,0x1F,0x20,0x20,0x00,0x00,//t 84
  0x80,0x80,0x00,0x00,0x00,0x80,0x80,0x00,0x00,0x1F,0x20,0x20,0x20,0x10,0x3F,0x20,//u 85
  0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x00,0x01,0x0E,0x30,0x08,0x06,0x01,0x00,//v 86
  0x80,0x80,0x00,0x80,0x00,0x80,0x80,0x80,0x0F,0x30,0x0C,0x03,0x0C,0x30,0x0F,0x00,//w 87
  0x00,0x80,0x80,0x00,0x80,0x80,0x80,0x00,0x00,0x20,0x31,0x2E,0x0E,0x31,0x20,0x00,//x 88
  0x80,0x80,0x80,0x00,0x00,0x80,0x80,0x80,0x80,0x81,0x8E,0x70,0x18,0x06,0x01,0x00,//y 89
  0x00,0x80,0x80,0x80,0x80,0x80,0x80,0x00,0x00,0x21,0x30,0x2C,0x22,0x21,0x30,0x00,//z 90
  0x00,0x00,0x00,0x00,0x80,0x7C,0x02,0x02,0x00,0x00,0x00,0x00,0x00,0x3F,0x40,0x40,//{ 91
  0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0xFF,0x00,0x00,0x00,//| 92
  0x00,0x02,0x02,0x7C,0x80,0x00,0x00,0x00,0x00,0x40,0x40,0x3F,0x00,0x00,0x00,0x00,//} 93
  0x00,0x06,0x01,0x01,0x02,0x02,0x04,0x04,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00,//~ 94
};
unsigned char code Hzk[][32]={

//{0x00,0x00,0xF0,0x10,0x10,0x10,0x10,0xFF,0x10,0x10,0x10,0x10,0xF0,0x00,0x00,0x00},
//{0x00,0x00,0x0F,0x04,0x04,0x04,0x04,0xFF,0x04,0x04,0x04,0x04,0x0F,0x00,0x00,0x00},/*"中",0*/

//{0x40,0x40,0x40,0x5F,0x55,0x55,0x55,0x75,0x55,0x55,0x55,0x5F,0x40,0x40,0x40,0x00},
//{0x00,0x40,0x20,0x0F,0x09,0x49,0x89,0x79,0x09,0x09,0x09,0x0F,0x20,0x40,0x00,0x00},/*"景",1*/

//{0x00,0xFE,0x02,0x42,0x4A,0xCA,0x4A,0x4A,0xCA,0x4A,0x4A,0x42,0x02,0xFE,0x00,0x00},
//{0x00,0xFF,0x40,0x50,0x4C,0x43,0x40,0x40,0x4F,0x50,0x50,0x5C,0x40,0xFF,0x00,0x00},/*"园",2*/

//{0x00,0x00,0xF8,0x88,0x88,0x88,0x88,0xFF,0x88,0x88,0x88,0x88,0xF8,0x00,0x00,0x00},
//{0x00,0x00,0x1F,0x08,0x08,0x08,0x08,0x7F,0x88,0x88,0x88,0x88,0x9F,0x80,0xF0,0x00},/*"电",3*/

//{0x80,0x82,0x82,0x82,0x82,0x82,0x82,0xE2,0xA2,0x92,0x8A,0x86,0x82,0x80,0x80,0x00},
//{0x00,0x00,0x00,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00,0x00,0x00,0x00},/*"子",4*/

//{0x24,0x24,0xA4,0xFE,0xA3,0x22,0x00,0x22,0xCC,0x00,0x00,0xFF,0x00,0x00,0x00,0x00},
//{0x08,0x06,0x01,0xFF,0x00,0x01,0x04,0x04,0x04,0x04,0x04,0xFF,0x02,0x02,0x02,0x00},/*"科",5*/

//{0x10,0x10,0x10,0xFF,0x10,0x90,0x08,0x88,0x88,0x88,0xFF,0x88,0x88,0x88,0x08,0x00},
//{0x04,0x44,0x82,0x7F,0x01,0x80,0x80,0x40,0x43,0x2C,0x10,0x28,0x46,0x81,0x80,0x00},/*"技",6*/


// 长(0) 春(1) 理(2) 工(3) 大(4) 学(5) 好(6) 好(7) 学(8) 习(9)

{0x80,0x80,0x80,0x80,0xFF,0x80,0x80,0xA0,0x90,0x88,0x84,0x82,0x80,0x80,0x80,0x00},
{0x00,0x00,0x00,0x00,0xFF,0x40,0x21,0x12,0x04,0x08,0x10,0x20,0x20,0x40,0x40,0x00},/*"长",0*/
/* (16 X 16 , 宋体 )*/

{0x40,0x44,0x54,0x54,0xD4,0x54,0x74,0x5F,0x54,0x54,0xD4,0x54,0x54,0x44,0x40,0x00},
{0x04,0x04,0x02,0x01,0xFE,0x92,0x92,0x92,0x92,0x92,0xFE,0x01,0x02,0x04,0x04,0x00},/*"春",1*/
/* (16 X 16 , 宋体 )*/

{0x04,0x84,0x84,0xFC,0x84,0x84,0x00,0xFE,0x92,0x92,0xFE,0x92,0x92,0xFE,0x00,0x00},
{0x20,0x60,0x20,0x1F,0x10,0x10,0x40,0x44,0x44,0x44,0x7F,0x44,0x44,0x44,0x40,0x00},/*"理",2*/
/* (16 X 16 , 宋体 )*/

{0x00,0x04,0x04,0x04,0x04,0x04,0x04,0xFC,0x04,0x04,0x04,0x04,0x04,0x04,0x00,0x00},
{0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x3F,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00},/*"工",3*/
/* (16 X 16 , 宋体 )*/

{0x20,0x20,0x20,0x20,0x20,0x20,0x20,0xFF,0x20,0x20,0x20,0x20,0x20,0x20,0x20,0x00},
{0x80,0x80,0x40,0x20,0x10,0x0C,0x03,0x00,0x03,0x0C,0x10,0x20,0x40,0x80,0x80,0x00},/*"大",4*/
/* (16 X 16 , 宋体 )*/

{0x40,0x30,0x11,0x96,0x90,0x90,0x91,0x96,0x90,0x90,0x98,0x14,0x13,0x50,0x30,0x00},
{0x04,0x04,0x04,0x04,0x04,0x44,0x84,0x7E,0x06,0x05,0x04,0x04,0x04,0x04,0x04,0x00},/*"学",5*/
/* (16 X 16 , 宋体 )*/

{0x10,0x10,0xF0,0x1F,0x10,0xF0,0x00,0x80,0x82,0x82,0xE2,0x92,0x8A,0x86,0x80,0x00},
{0x40,0x22,0x15,0x08,0x16,0x61,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00},/*"好",6*/
/* (16 X 16 , 宋体 )*/

{0x10,0x10,0xF0,0x1F,0x10,0xF0,0x00,0x80,0x82,0x82,0xE2,0x92,0x8A,0x86,0x80,0x00},
{0x40,0x22,0x15,0x08,0x16,0x61,0x00,0x00,0x40,0x80,0x7F,0x00,0x00,0x00,0x00,0x00},/*"好",7*/
/* (16 X 16 , 宋体 )*/

{0x40,0x30,0x11,0x96,0x90,0x90,0x91,0x96,0x90,0x90,0x98,0x14,0x13,0x50,0x30,0x00},
{0x04,0x04,0x04,0x04,0x04,0x44,0x84,0x7E,0x06,0x05,0x04,0x04,0x04,0x04,0x04,0x00},/*"学",8*/
/* (16 X 16 , 宋体 )*/

{0x00,0x02,0x02,0x02,0x12,0x22,0xC2,0x02,0x02,0x02,0x02,0x02,0xFE,0x00,0x00,0x00},
{0x00,0x08,0x18,0x08,0x04,0x04,0x04,0x02,0x02,0x41,0x81,0x40,0x3F,0x00,0x00,0x00},/*"习",9*/
/* (16 X 16 , 宋体 )*/

};

#endif

/* ==================== Uart\uart.c ==================== */
#include "uart.h"
#include "main.h"

//串口发送一个字节
void UART_Send_Byte(uchar send_byte)
{
	SBUF = send_byte;
	while(!TI);
	TI=0;
}

//串口发送字符串
void UART_Send_Str(uchar *send_str)
{	
	while(*send_str != '\0') //判断字符串结束符,如果识别到‘\0',则跳出while,结束发送
	{
		UART_Send_Byte(*send_str++);	//本质是一个字节一个字节的发送,
		//发送完一个字节,地址+1,等待发送下一个字节,直到检测到字符串结束符为止
	}	
} 

void UART_Init(void)
{
	SCON = 0x50; 	//串口配成工作方式1
	PCON &= 0x7F; //波特率不加倍
	TMOD &= 0x0f;	
	TMOD |= 0x20;	//定时器1,模式二,自动重装初值,串口按照一定速率发数据,需要用的定时器
	TH1 = 0xFD;	
	TL1 = 0xFD; //@11.0592MH时钟,9600比特率定时器初值
	TR1 = 1; //定时器开始运行   
	ES = 1;  //串口中断打开
	EA=1;					//总中断打开
	recv = 0;
}

/* ==================== Uart\uart.h ==================== */
#ifndef _UART_H_
#define _UART_H_
#include "main.h"

void UART_Send_Byte(uchar send_byte);
void UART_Send_Str(uchar *send_str);
void UART_Init(void);

#endif

一、DHT11驱动代码

DHT11 驱动可以拆成三层:GPIO 与延时负责产生波形,协议层负责启动和接收 40 位数据,应用层负责校验、格式化并送往 OLED。这样组织后,电路、时序和代码能够逐项对应。

1.1 任务分析

本阶段以已经能够驱动 OLED 的工程为基础,增加独立的 DHT11 模块:

工程
├─ main.c / main.h       应用流程与公共引脚
├─ Delay/
│  ├─ delay.c
│  └─ delay.h            毫秒、微秒延时
├─ DHT11/
│  ├─ dht11.c            启动与读数据
│  └─ dht11.h            对外接口声明
├─ IIC/                  OLED使用的软件I²C
├─ OLED/
└─ Uart/

模块化的关键不是文件夹名称,而是职责边界:

  • dht11.c 只处理 DHT11 协议,不直接绘制 OLED。
  • dht11.h 只暴露调用者需要的函数声明。
  • main.c 决定多久采样一次、成功时显示什么、失败时如何处理。
  • main.h 中集中定义硬件引脚,保证接线和代码一致。

1.2 添加文件

在 Keil 工程目录中新建 DHT11 文件夹,再建立 dht11.c、dht11.h。将 dht11.c 添加到工程分组,并把 DHT11 文件夹加入 C51 的 Include Paths。

仅把文件放进磁盘目录并不等于加入工程:

操作解决的问题
Add Existing Files to Group让 dht11.c 参与编译和链接
配置 Include Paths让编译器能够搜索到 dht11.h
在调用处写 include让当前编译单元获得函数声明
在头文件中加包含保护防止同一声明被重复展开

头文件包含保护应写成:

#ifndef _DHT11_H_
#define _DHT11_H_

void DHT11_Start(void);
void DHT11_Read(unsigned char *humi, unsigned char *temp);

#endif

1.3 包含其他文件

dht11.c 需要访问引脚和延时函数,因此包含关系为:

flowchart LR
    D[dht11.c] --> H[dht11.h]
    D --> M[main.h:DHT11_IO]
    D --> L[delay.h:Delay_xms/Delay30us]
    A[main.c] --> H

include 只能提供声明,函数实体仍须由对应的 c 文件参与编译。出现“函数未定义”时要区分两类问题:

  • 编译阶段提示未声明:通常缺少头文件或声明不匹配。
  • 链接阶段提示 unresolved external:通常对应 c 文件未加入工程,或函数名不一致。

声明与定义的返回类型、函数名、参数个数和参数类型必须完全一致。

1.4 编写DHT11驱动代码

先实现启动握手,再实现逐位接收。每一步都应能在手册时序图中找到依据:

flowchart TD
    A[MCU拉低DATA至少18 ms] --> B[MCU释放DATA 20~40 μs]
    B --> C{检测DHT约80 μs低响应}
    C -->|检测到上升沿| D{检测约80 μs高响应}
    D -->|检测到下降沿| E[连续读取5字节]
    E --> F[比较校验和]
1.4.1 电路总线

配套代码使用 P1.2:

sbit DHT11_IO = P1^2;

实际连接应为:

VCC ─────────────── DHT11 VCC
 │
 └──[约5 kΩ上拉]─── DATA ───────── P1.2
GND ─────────────── DHT11 GND ───── 51 GND

上拉电阻使 DATA 空闲为高。P1.2 写 0 时单片机主动拉低;在经典 8051 准双向端口上写 1 后,端口才被释放,DHT11 才能驱动该线。不能把“写 1”简单理解为双方都可以同时输出高电平;换用推挽 GPIO 时应切换到开漏或输入模式,避免总线争用。

开发板上 P1.2 同时连接低电平点亮的 LED3,通信时灯可能闪动。该 LED 支路会形成额外负载,所以接线正确却波形异常时,应把共用引脚负载也纳入检查。

1.4.2 单总线通信

DHT11 协议只有 DATA 一根信号线,但通信控制权会切换:

阶段DATA 控制者动作
空闲上拉电阻保持高电平
启动MCU低至少 18 ms
等待MCU释放高 20~40 μs
响应DHT11低约 80 μs、高约 80 μs
数据DHT11发送 40 位,最高位先发
结束DHT11释放上拉恢复高电平

这里无需像 I²C 那样发送设备地址,也没有 ACK 位。DHT11 是主机发起一次读取、传感器紧接着回传固定数据帧的器件专用协议。

1.4.3 时序

启动函数的核心操作如下:

DHT11_IO = 0;
Delay_xms(20);       // 大于手册要求的18 ms
DHT11_IO = 1;        // 经典8051上相当于释放总线
Delay30us();         // 位于20~40 μs等待窗口

30 μs 延时必须按 11.0592 MHz 晶振和目标芯片指令集生成。软件延时依赖晶振、编译优化和函数调用开销,移植到其他芯片时不能照抄循环次数。

配套函数随后用两个 while 等待边沿。它依赖传感器一定会响应,因此传感器拔掉、接反或线路断开时可能永久卡在循环中。学习时可以先理解边沿检测,实际程序必须加入超时;超时版会在后续优化阶段实现。

1.4.4 响应信号

在 MCU 释放线路后,DHT11 的响应为先低后高:

MCU等待       DHT响应低           DHT响应高        第1位起始低
‾‾‾‾‾‾________________/‾‾‾‾‾‾‾‾____________
20~40 μs        约80 μs              约80 μs          约50 μs
        ↑ while(!IO)等待到这里结束
                              ↑ while(IO)等待到这里结束

两条语句的逻辑是:

while(!DHT11_IO);   // IO为0时继续等待,看到上升沿后退出
while(DHT11_IO);    // IO为1时继续等待,看到下降沿后退出

第一条并不是“等待低电平出现”,而是已经处于低电平时等待它结束;第二条同理,是等待高电平结束。若在错误的相位进入循环,程序可能把响应脉冲和第一个数据位混淆,所以必须先按照手册保证释放与采样时刻。

可靠实现还要处理三种异常:等待拉低超时、低脉冲不结束、高脉冲不结束。仅检测电平而不设超时,无法区分正常边沿和硬件故障。

1.4.5 数据传输过程

DHT11 固定回传 5 字节:

byte0          byte1          byte2          byte3          byte4
湿度整数       湿度小数       温度整数       温度小数       校验和
  8 bit          8 bit          8 bit          8 bit          8 bit
└────────────────────── 前四字节求和取低8位 ──────────────────┘

每个数据位都以约 50 μs 低电平开始,随后高电平宽度决定 0 或 1:

  • 约 26~28 μs 高电平:位 0。
  • 约 70 μs 高电平:位 1。
  • DHT11 最高位先发,因此接收一位后可先左移,再把当前位并入最低位。

校验必须理解成八位运算:

checksum = (byte0 + byte1 + byte2 + byte3) & 0xFF;

DHT11 的小数字节通常为 0,但它们仍然属于数据帧和校验计算,不能少读。一次读取结束后至少间隔 1 s 再发起下一次通信。