main函数
#include "stm32f10x.h"
#include "delay.h"
#include "usart.h"
#include "led.h"
#include "BH1750.h"
#include "dht11.h"
#include "lcd1602.h"
#include "IIC.h"
#include "pwm_output.h"
#include "key.h"
#include "adc.h"
u8 temp; //unsigned char无符号字节型,8位
u8 humi;
int speed=52;
extern unsigned char revaa[100]; //exern变量或者函数的定义在别的文件中,提示编译器遇到此变量和函数时在其他模块中寻找其定义
extern float lux;
u16 adcx;
int main(void)
{
int worn=0;
int temp_bai,temp_shi,temp_ge; //温度的个、十、百
int humi_bai,humi_shi,humi_ge; //湿度的个、十、百
int guang_bai,guang_shi,guang_ge; //光照的个、十、百
int speed_bai,speed_shi,speed_ge; //可能是电机的速度
delay_init(); //延时函数
Adc_Init(); //将模拟形式的连续信号转换为数字形式的离散信号
uart_init(115200); //串口初始化函数,串口初始化为9600
Init_LEDpin();
GPIO_Configuration(); //配置GPIO,通用输入/输出端口,通俗地说,就是一些引脚,可以通过它们输出高低电平或者通过它们读入引脚的状态-是高电平或是低电平。
LCD1602_Init(); //液晶初始化函数
BH1750_Init(); //光照强度函数
TIM3_PWM_Init(); //PWM初始化函数定义。PWM是利用微处理器的数字输出来对模拟电路进行控制的一种非常有效的技术
[PWM](https://www.cnblogs.com/brianblog/p/7117896.html)
KEY_Init(); //按键初始化
[key](https://blog.csdn.net/qq_47348951/article/details/113078914)
printf("AT+RST\r\n"); //重启模块
delay_ms(3000); //单片机执行命令的速度太快,加入延时来放慢端口电平的变化速度
delay_ms(3000);
printf("AT+CIPMUX=1\r\n"); //开启多连接模式,可支持多个客户端的连接
delay_ms(3000);
delay_ms(3000);
printf("AT+CIPSERVER=1,8089\r\n"); //开启服务器,并监听8089端口
delay_ms(3000);
delay_ms(3000);
while(DHT11_Init())//温湿度传感器
{
}
while(1)
{
adcx=Get_Adc_Average(ADC_Channel_1,10); //得到ADC转换值
speed_bai=adcx/100;
speed_shi=adcx%100/10; //%求余数 /除法
speed_ge=adcx%10;
DHT11_Read_Data(&temp,&humi); //[温湿度传感器DHT11,从DHT11读取一次数据](https://blog.csdn.net/qq_42930154/article/details/104532523)
temp_bai=temp/100;
temp_shi=temp%100/10;
temp_ge=temp%10;
humi_bai=humi/100;
humi_shi=humi%100/10;
humi_ge=humi%10;
//显示屏显示的数据//T:029H:075G:079
//PM:052
LCD1602_Show_String(0,0,2,"T:"); //调用函数(表示字符在LCD显示的横轴x的起始坐标,y,长度,数值)
LCD1602_Show_Num(2,0,temp_bai); //调用函数,输入值,让显示屏显示即可
LCD1602_Show_Num(3,0,temp_shi);
LCD1602_Show_Num(4,0,temp_ge);
LCD1602_Show_String(5,0,2,"H:");
LCD1602_Show_Num(7,0,humi_bai);
LCD1602_Show_Num(8,0,humi_shi);
LCD1602_Show_Num(9,0,humi_ge);
// printf("H:%d\r\n",humi);
BH1750_ReadContinuous1(); //调用光照强度的函数
printf("AT+CIPSEND=0,38\r\n"); //将一些传感器数据发送到TCP服务器,不知道是怎么发的“\ r”是回车符,“\ n”是新行
delay_ms(20);
//printf("temp:%d--humi:%d--lux:%d--dat:%d",temp,humi,(int)lux,speed);
printf("温度:%2d\r\n湿度:%2d\r\n光照:%3d\r\nPM2.5:%2d\r\n",temp,humi,(int)lux,adcx); //这个是在手机app上的,lux是光照,adcx是pm2.5
delay_ms(200);
guang_bai=(int)lux/100;
guang_shi=(int)lux%100/10;
guang_ge=(int)lux%10;
LCD1602_Show_String(10,0,2,"G:");
LCD1602_Show_Num(12,0,guang_bai);
LCD1602_Show_Num(13,0,guang_shi);
LCD1602_Show_Num(14,0,guang_ge);
LCD1602_Show_String(0,1,3,"PM:"); //有参数可以看出在第二行了
LCD1602_Show_Num(3,1,speed_bai);
LCD1602_Show_Num(4,1,speed_shi);
LCD1602_Show_Num(5,1,speed_ge);
if(revaa[10]=='1')//开灯
{
revaa[10]=0xff;
GPIO_ResetBits(GPIOC,GPIO_Pin_13); //reset为0 //LED灯
}
if(revaa[10]==0x32)//关灯
{
revaa[10]=0xff; //全为1,高电平,不知道什么意思
GPIO_SetBits(GPIOC,GPIO_Pin_13); //set为1 //LED灯
}
if(revaa[10]==0x33)//开风扇
{
revaa[10]=0xff;
GPIO_SetBits(GPIOC,GPIO_Pin_14); //LED灯
}
if(revaa[10]==0x34)//关风扇
{
revaa[10]=0xff;
GPIO_ResetBits(GPIOC,GPIO_Pin_14); //LED灯
}
if(revaa[10]==0x35)//开加湿器
{
revaa[10]=0xff;
GPIO_SetBits(GPIOC,GPIO_Pin_15); //LED灯
}
if(revaa[10]==0x36)//关加湿器
{
revaa[10]=0xff;
GPIO_ResetBits(GPIOC,GPIO_Pin_15); //LED灯
}
if(revaa[10]==0x37)//开窗帘
{
revaa[10]=0xff;
GPIO_SetBits(GPIOA,GPIO_Pin_0); //set是设置为1 //LED灯
}
if(revaa[10]==0x38)//关窗帘
{
revaa[10]=0xff;
GPIO_ResetBits(GPIOA,GPIO_Pin_0); //reset就是设置为0 //LED灯
}
}
}
usart文件(向串口发送字节数据函数,配置串口1和串口2,向串口发送字符串数据函数(单片机发给WiFi模块),串口1中断服务程序(WiFi模块发给单片机控制指令后产生中断))
#include "sys.h"
#include "usart.h"
#include "stdio.h"
#include "string.h"
#include "stm32f10x_tim.h"
unsigned char uart1_getok;
//
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1 /*printf() 之类的函数,使用了半主机模式。使用标准库会导致程序无法运行,为了继续使用标准库 ,要添加下面代码,为确保没有从 C 库链接使用半主机的函数,因为不使用半主机,标准 C 库 stdio.h 中有些使用半主机的
函数要重新写 ,您必须为这些函数提供自己的实现 */
#pragma import(__use_no_semihosting) // 确保没有从 C 库链接使用半主机的函数
struct __FILE //标准库需要的支持函数
{
int handle;
};
[相关链接](https://blog.csdn.net/tao658/article/details/81204094)
unsigned char revaa[100];
int revaa_num=0;
FILE __stdout;
_sys_exit(int x) //定义—sys_exit()以避免使用半主机模式
{
x = x;
}
//重定义fputc函数。标准库函数的默认输出设备是显示器, 要实现在串口或 LCD 输出,必须重定义标准库函数里调用的与输出,printf 输出到串口,需要将 fputc 里面的输出指向串口 (重定向 ),链接在上面
int fputc(int ch, FILE *f)
{
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕 &0X40就是让SR寄存器的第七位置一
USART1->DR = (u8) ch;
return ch;
}
[链接](http://www.openedv.com/posts/list/29268.htm)
#endif
void UART1_send_byte(char data) //STM32串口发送字节数据
{
while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET); //USART_GetFlagStatus获取串口相关的状态寄存器信息的等待发送完成。 检测 USART_FLAG_TXE是否置1
USART_SendData(USART1, data); 通过库函数 向串口1发送数据
}
void UART2_send_byte(char data)
{
while(USART_GetFlagStatus(USART2, USART_FLAG_TXE) == RESET);
USART_SendData(USART2, data);
}
//PC上位机模块PC上位机模块实现PC机对步进电机的控制。利用MSP430单片机的USART模块实现与PC上位机的通信,PC机通过串口向单片机发送控制命令,实现电机控制。单片机所接收到控制命令暂存在RXBUFFER中,然后与存储在片内Flash的中断程序的入口地址相比较,相同就进入中断,实现步进电机的控制。
//串口1中断服务程序
//注意,读取USARTx——>SR能避免莫名其妙的错误
unsigned char RxCounter,RxBuffer[255]; //接受缓冲,最大255个字节
char RxCounter1,RxBuffer1[100]; //接收缓冲,最大100个字节。
接收状态
//bit15, 接收完成标志0x0a
//bit14, 接收到0X0d标志
//bit13~0, 接收到的有效数据个数
u16 USART_RX_STA=0; //接收状态标记,没有用到
extern u8 Timeout;
//初始化IO串口1
//bound:波特率
void uart_init(u32 bound){ //串口初始化函数
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1|RCC_APB2Periph_GPIOA, ENABLE); //使能UsART1,GPTOA时钟
USART_DeInit(USART1); //复位串口1
//USART1_TX PA.9
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化 GPIOA.9
//USART1_RX PA.10
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//USART1_RX PA.10
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化 GPIOA.10
//Usart1 NVIC配置
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;//抢占优先级3
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 3; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化VIc寄存器,//中断优先级初始化
//USART 初始化设置
USART_InitStructure.USART_BaudRate = bound;//波特率设置,一般设置为9600;
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART1, &USART_InitStructure); //初始化串口
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启接收中断
USART_Cmd(USART1, ENABLE); //使能串口
}
//初始化Io串2
//bound:波特率
void uart2_init(u32 bound)
{
//GPIO端口设置
GPIO_InitTypeDef GPIO_InitStructure;
USART_InitTypeDef USART_InitStructure;
NVIC_InitTypeDef NVIC_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能,GPIOA时钟
RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2,ENABLE);//USART2
USART_DeInit(USART2); //复位串口2
//USART2_TX PA.2
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; //PA.2
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP; //复用推挽输出
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA2
//USART2_RX PA.3
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化PA3
//Usart1 NvIC配置
NVIC_InitStructure.NVIC_IRQChannel = USART2_IRQn;
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=0 ;//抢占优先级0
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1; //子优先级3
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE; //IRQ通道使能
NVIC_Init(&NVIC_InitStructure); //根据指定的参数初始化vIc寄存器
//USART初始化设置
USART_InitStructure.USART_BaudRate = bound;//115200
USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字节为8位数据格式
USART_InitStructure.USART_StopBits = USART_StopBits_1;//一个停止位
USART_InitStructure.USART_Parity = USART_Parity_No;//无奇偶校验位
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None;//无硬件数据流控制
USART_InitStructure.USART_Mode = USART_Mode_Rx | USART_Mode_Tx; //收发模式
USART_Init(USART2, &USART_InitStructure); //初始化串口
USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);//开启中断
USART_Cmd(USART2, ENABLE); //使能串口
}
[上面两段很长的代码,就是串口1和串口2的初始化](https://blog.csdn.net/qq_46626969/article/details/107220770)
void Uart1_SendStr(char*SendBuf)// 向串口1打印数据(发送字符串函数)
{
while(*SendBuf)
{
while((USART1->SR&0X40)==0);//等待发送完成,要检测这个数据是否已经被发送完成了通过之后,要检测这个数据是否已经被发送完成了通过之后,要检测这个数据是否已经被发送完成了通过USART1->SR的第6位,是否为1来决定是否可以开始第二个字节的发送。0x40二进制是1000000
USART1->DR = (u8) *SendBuf; //USART1->DR是一个数据寄存器,包括TDR和RDR,当向该数据寄存器写数据的时候,会自动向串口发送数据,这句话就是将接收缓存送至该数据寄存器,同时发送到串口。
SendBuf++;
}
}
void USART1_IRQHandler(void) //串口1中断服务程序
{
u8 Res;
if(USART_GetITStatus(USART1, USART_IT_RXNE) != RESET) //接收中断(接收到的数据必须是0x0d 0x0a结尾)(0x0D是回车的ASCLL码,0x0A是换行的ASCLL码)
{
Res =USART_ReceiveData(USART1); //读取接收到的数据
if(Res==0x2b)
{
revaa_num=0;
}
revaa[revaa_num]=Res;
revaa_num++;
}
[相关代码](https://blog.csdn.net/milu_yu/article/details/108523888)
}
delay文件(头文件,锁调度,开锁调度,延时函数,初始化延时函数,不使用ucos系统时和使用ucos系统的延时函数,其中还有ms和ns的两种情况)
//当使用ucos时才有以下部分:主要实现宏定义与基本函数定义。
#include "delay.h"
//如果需要使用os,则包括下面的头文件即可,os是操作系统的意思
#if SYSTEM_SUPPORT_OS
#include "includes.h" //ucos 使用
#endif
static u8 fac_us=0; //us延时倍乘数
static u16 fac_ms=0; //us延时倍乘数,在ucos下,代表每个节拍的ms数
#if SYSTEM_SUPPORT_OS //如果SYSTEM_SUPPORT_OS定义了,说明要支持OS了(不限于UCOS).
//当delay_us/delay_ms需要支持OS的时候需要三个与OS相关的宏定义和函数来支持
//首先是3个宏定义:
// delay_osrunning:用于表示OS当前是否正在运行,以决定是否可以使用相关函数
//delay_ostickspersec:用于表示OS设定的时钟节拍,delay_init将根据这个参数来初始哈systick
// delay_osintnesting:用于表示OS中断嵌套级别,因为中断里面不可以调度,delay_ms使用该参数来决定如何运行
//然后是3个函数:
// delay_osschedlock:用于锁定OS任务调度,禁止调度
//delay_osschedunlock:用于解锁OS任务调度,重新开启调度
// delay_ostimedly:用于OS延时,可以引起任务调度.
//[ucos是一个操作系统,两个版本:UCOSII和UCOSIII](https://blog.csdn.net/weixin_38847128/article/details/84391783)
//本例程仅作UCOSII和UCOSIII的支持,其他OS,请自行参考着移植
//支持UCOSII
#ifdef OS_CRITICAL_METHOD //OS_CRITICAL_METHOD定义了,说明要支持UCOSII
#define delay_osrunning OSRunning //OS是否运行标记,0,不运行;1,在运行
#define delay_ostickspersec OS_TICKS_PER_SEC //OS时钟节拍,即每秒调度次数
#define delay_osintnesting OSIntNesting //中断嵌套级别,即中断嵌套次数
#endif
//支持UCOSIII
#ifdef CPU_CFG_CRITICAL_METHOD //CPU_CFG_CRITICAL_METHOD定义了,说明要支持UCOSIII
#define delay_osrunning OSRunning //OS是否运行标记,0,不运行;1,在运行
#define delay_ostickspersec OSCfg_TickRate_Hz //OS时钟节拍,即每秒调度次数
#define delay_osintnesting OSIntNestingCtr //中断嵌套级别,即中断嵌套次数
#endif
//OSSchedLock()和OSSchedUnlock()函数允许应用程序锁定当前任务不被其它任务抢占,两个函数成对出现
//us级延时时,关闭任务调度(防止打断us级延迟)用于锁定os任务调度,禁止调度
void delay_osschedlock(void)
{
#ifdef CPU_CFG_CRITICAL_METHOD //使用UCOSIII
OS_ERR err;
OSSchedLock(&err); //UCOSIII的方式,禁止调度,防止打断us延时
#else //否则UCOSII
OSSchedLock(); //UCOSII的方式,禁止调度,防止打断us延时
#endif
}
//us级延时时,恢复任务调度用于解锁os任务调度,重新开启调度
void delay_osschedunlock(void)
{
#ifdef CPU_CFG_CRITICAL_METHOD //使用UCOSIII
OS_ERR err;
OSSchedUnlock(&err); //UCOSIII的方式,恢复调度
#else //否则UCOSII
OSSchedUnlock(); //UCOSII的方式,恢复调度
#endif
}
//调用OS自带的延时函数延时
//ticks:延时的节拍数,用于os延时,可以引起任务调度。
void delay_ostimedly(u32 ticks)
{
#ifdef CPU_CFG_CRITICAL_METHOD
OS_ERR err;
OSTimeDly(ticks,OS_OPT_TIME_PERIODIC,&err); //UCOSIII延时采用周期模式
#else
OSTimeDly(ticks); //UCOSII延时
#endif
}
//systick中断服务函数,使用ucos时用到
//中断服务函数,在STK_VAL寄存器中的数值置0时,并且TICkINT触发异常使能位为1时,会产生SysTick中断,在SysTick_Config()函数中会调用NVIC_SetPriority()函数配置SysTick中断
void SysTick_Handler(void)
{
if(delay_osrunning==1) //OS开始跑了,才执行正常的调度处理
{
OSIntEnter(); //进入中断
OSTimeTick(); //调用ucos的时钟服务程序
OSIntExit(); //触发任务切换软中断
}
}
#endif
//初始化延迟函数
//当使用OS的时候,此函数会初始化OS的时钟节拍
//SYSTICK的时钟固定为HCLK时钟的1/8
//SYSCLK:系统时钟
void delay_init()
{
#if SYSTEM_SUPPORT_OS //如果需要支持OS.
u32 reload;
#endif
SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8); //选择外部时钟 HCLK/8
fac_us=SystemCoreClock/8000000; //为系统时钟的1/8
#if SYSTEM_SUPPORT_OS //如果需要支持OS.
reload=SystemCoreClock/8000000; //每秒钟的计数次数 单位为M
reload*=1000000/delay_ostickspersec; //根据delay_ostickspersec设定溢出时间
//reload为24位寄存器,最大值:16777216,在72M下,约合1.86s左右
fac_ms=1000/delay_ostickspersec; //代表OS可以延时的最少单位
SysTick->CTRL|=SysTick_CTRL_TICKINT_Msk; //开启SYSTICK中断
SysTick->LOAD=reload; //每1/delay_ostickspersec秒中断一次
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk; //开启SYSTICK
#else
fac_ms=(u16)fac_us*1000; //非OS下,代表每个ms需要的systick时钟数
#endif
}
//下面是使用ucos的delay函数
#if SYSTEM_SUPPORT_OS //如果需要支持OS.
//延时nus
//nus为要延时的us数.
//[us和ms的区别](https://zhidao.baidu.com/question/523052448.html)一个微秒一个毫秒
void delay_us(u32 nus)
{
u32 ticks;
u32 told,tnow,tcnt=0;
u32 reload=SysTick->LOAD; //LOAD的值
ticks=nus*fac_us; //需要的节拍数
tcnt=0;
delay_osschedlock(); //阻止OS调度,防止打断us延时
told=SysTick->VAL; //刚进入时的计数器值
while(1)
{
tnow=SysTick->VAL;
if(tnow!=told)
{
if(tnow<told)tcnt+=told-tnow; //这里注意一下SYSTICK是一个递减的计数器就可以了.
else tcnt+=reload-tnow+told;
told=tnow;
if(tcnt>=ticks)break; //时间超过/等于要延迟的时间,则退出.
}
};
delay_osschedunlock(); //恢复OS调度
}
//延时nms
//nms:要延时的ms数
void delay_ms(u16 nms)
{
if(delay_osrunning&&delay_osintnesting==0) //如果OS已经在跑了,并且不是在中断里面(中断里面不能任务调度)
{
if(nms>=fac_ms) //延时的时间大于OS的最少时间周期
{
delay_ostimedly(nms/fac_ms); //OS延时
}
nms%=fac_ms; //OS已经无法提供这么小的延时了,采用普通方式延时
}
delay_us((u32)(nms*1000)); //普通方式延时
}
#else //不用OS时
//下面两个是不使用ucos的delay函数
//延时nus
//nus为要延时的us数.
void delay_us(u32 nus)
{
u32 temp;
SysTick->LOAD=nus*fac_us; //时间加载
SysTick->VAL=0x00; //清空计数器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
//延时nms
//注意nms的范围
//SysTick->LOAD为24位寄存器,所以,最大延时为:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK单位为Hz,nms单位为ms
//对72M条件下,nms<=1864
void delay_ms(u16 nms)
{
u32 temp;
SysTick->LOAD=(u32)nms*fac_ms; //时间加载(SysTick->LOAD为24bit)
SysTick->VAL =0x00; //清空计数器
SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ; //开始倒数
do
{
temp=SysTick->CTRL;
}while((temp&0x01)&&!(temp&(1<<16))); //等待时间到达
SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}
#endif
[上面的代码](https://blog.csdn.net/weixin_42038628/article/details/102608622)
sys文件(下面的文件好像没有调用到,不清楚)
#include "sys.h"
//THUMB指令不支持汇编内联(thuma指令是arm指令的子集,汇编内联指在C语言中插入汇编语言)
//采用如下方法实现执行汇编指令WEI
void WFI_SET(void)
{
__ASM volatile("wfi"); //__asm__ __volatile__("");是汇编内联的表达式。汇编内联的方法,wfi指令用来实现[关闭clock、保持供电](http://www.wowotech.net/armv8a_arch/wfe_wfi.html)
}
//关闭所有中断
void INTX_DISABLE(void)
{
__ASM volatile("cpsid i");
}
//开启所有中断
void INTX_ENABLE(void)
{
__ASM volatile("cpsie i");
}
//设置栈顶地址
//addr:栈顶地址
__asm void MSR_MSP(u32 addr)
{
MSR MSP, r0 //set Main Stack value
BX r14
}
BH1750文件(单次写函数,BH1750初始化,连续读函数)
#include "BH1750.h"
#include "delay.h"
#include "IIC.h"
#include "sys.h"
#include "stm32f10x.h"
#include <stdint.h>
u8 BUF[8];
u16 temp2=0;
float lux=0;
/****向BH1750单次写命令****/(这个函数被BH1750初始化时调用了)
void Single_Write_BH1750(unsigned char Reg_Address)
{
IIC_Start();
IIC_Send_Byte(0x46); //发送器件地址01000110最后一位o,表示写
//IIC_Wait_Ack();
IIC_Send_Byte(Reg_Address); //内部寄存器地址
//IIC_Wait_Ack();
IIC_Stop(); //发送停止信号
}
/****BH1750初始化****/
void BH1750_Init(void)
{
IIC_Config();
Single_Write_BH1750(0x01);
}
/****从BH1750单次读Lux****/(好像也没有用到,因为没有调用到它)
/**模式选择;H-Resolution Mode,分辨率11ux单次读Opecode:00100000,即0x20 器件地址:0100011,ADDR接GND
void BH1750_ReadOneTime(void)
{
IIC_Start();
IIC_Send_Byte(0x46); //发送器件地址0100 0110 最后一位0,表示写
IIC_Wait_Ack();
IIC_Send_Byte(0x20); //发送One time H-Resolution Mode的Opecode 0010 0000,分辨率为1lux
IIC_Wait_Ack();
IIC_Stop();
delay_ms(200);
IIC_Start();
IIC_Send_Byte(0x47); //
IIC_Wait_Ack();
BUF[0]=IIC_Read_Byte(1);
//IIC_Ack(); //主机应答
//temp1=temp<<8;
BUF[1]=IIC_Read_Byte(0);
//IIC_NAck(); //主机不应答
IIC_Stop();
// temp2=BUF[0];
// temp2=(temp2<<8)+BUF[1];
// lux=(float)temp2/1.2; //lux是float型
//return lux;
//delay_ms(200);
}
/****从BH1750连续读Lux****/(用了这个连续读函数)
/****
模式选择:H-Resolution Mode,分辨率1lux
连续读Opecode:0001 0000
器件地址:0100011,ADDR接GND
****/
void bh1
void BH1750_ReadContinuous1(void)
{
u16 temp=0,temp1=0;
IIC_Start();
IIC_Send_Byte(0x46); //发送器件地址0100 0110 最后一位0,表示写
IIC_Wait_Ack();
IIC_Send_Byte(0x10); //发送Continuous H-Resolution Mode的Opecode 0001 0000,分辨率为1lux
IIC_Wait_Ack();
IIC_Stop();
delay_ms(200);
IIC_Start();
IIC_Send_Byte(0x47);
IIC_Wait_Ack();
// BUF[0]=IIC_Read_Byte(1);
// BUF[1]=IIC_Read_Byte(0);
temp=IIC_Read_Byte(1);
temp1=IIC_Read_Byte(0);
IIC_Stop();
temp2=temp1+(temp<<8);
lux=(float)temp2/1.2; //luxÊÇfloatÐÍ
}
/****方法二:****/(没用到)
void BH1750_ReadContinuous2(void)
{
//u16 temp=0,temp1=0;
IIC_Start();
IIC_Send_Byte(0x46); //发送器件地址01000110最后一位0,表示写
IIC_Wait_Ack();
IIC_Send_Byte(0x10); //发送Continuous H-Resolution Mode的opecode 00010000,分辨率为1lux
IIC_Wait_Ack();
IIC_Stop();
delay_ms(200);
IIC_Start();
IIC_Send_Byte(0x47);
IIC_Wait_Ack();
BUF[0]=IIC_Read_Byte(1);
BUF[1]=IIC_Read_Byte(0);
// temp=IIC_Read_Byte(1);
// temp1=IIC_Read_Byte(0);
IIC_Stop();
// temp2=temp1+(temp<<8);
// lux=(float)temp2/1.2; //lux是float型
}
/****方法三****/(没用到)
/****
利用函数BH1750_Multiple_Read()进行读
利用Conversion(void)函数进行转换
void BH1750_Multiple_Read(void)
{
IIC_Start();
IIC_Send_Byte(0x47);
BUF[0]=IIC_Read_Byte(1);
BUF[1]=IIC_Read_Byte(0);
IIC_Stop(); //停止信号
delay_us(5);
delay_ms(200);
}
void Conversion(void)
{
temp2=BUF[0];
temp2=(temp2<<8)+BUF[1];
lux=(float)temp2/1.2; //lux是float型
}
dht11
1.MCU如何设置开始信号?(MCU跟DHT11说:你可以开始工作了)
由MCU向DHT11发送一次开始信号,总线空闲状态为高电平,MCU把总线拉低至少18ms,
保证DHT11能检测到开始信号,主机发送开始信号后,可以切换到输入模式,或者切换到
高电平均可,切换到高电平时间通常为20~40us,然后开始读取响应信号.
2.MCU如何接受响应信号?(MCU需要听到DHT11的回复,1或者0)
等待DHT11的回应
返回1:未检测到DHT11的存在
返回0:存在DHT11接受到主机的开始信号后,等待主机的开始信号结束,
然后发送80us的低电平响应信号,发送响应信号后,在把总线拉高80us,准备发送数据*/
/***************STM32F103C8T6**********************
*文件名:DHT11.c
*描述:DHT11传感器
*备注:DHT11温度湿度传感器
*接口:PA11-DATA
********************LIGEN*************************/
#include "dht11.h"
#include "delay.h"
#define DT GPIO_Pin_3
//复位DHT11
void DHT11_Rst(void)
{
DHT11_IO_OUT(); //SET OUTPUT
DHT11_DQ_OUT=0; //拉低DQ
delay_ms(20); //拉低至少18ms
DHT11_DQ_OUT=1; //DQ=1
delay_us(30); //主机拉高20~40us
}
//等待DHT11的回应,判断响应模块
//返回1:未检测到DHT11的存在
//返回0:存在
u8 DHT11_Check(void)
{
u8 retry=0;
DHT11_IO_IN();//SET INPUT
while (DHT11_DQ_IN&&retry<100)//DHT11会拉低40~80us
{
retry++;
delay_us(1);
};
if(retry>=100)return 1;
else retry=0;
while (!DHT11_DQ_IN&&retry<100)//DHT11拉低后会再次拉高40~80us
{
retry++;
delay_us(1);
};
if(retry>=100)return 1;
return 0;
}
//从DHT11读取一个位
//返回值:1/0
u8 DHT11_Read_Bit(void)
{
u8 retry=0;
while(DHT11_DQ_IN&&retry<100)//等待变为低电平
{
retry++;
delay_us(1);
}
retry=0;
while(!DHT11_DQ_IN&&retry<100)//等待变高电平
{
retry++;
delay_us(1);
}
delay_us(40);//等待40us
if(DHT11_DQ_IN)return 1;
else return 0;
}
//从DHT11读取一个字节(一个字节8位)
//返回值:读到的数据
u8 DHT11_Read_Byte(void)
{
u8 i,dat;
dat=0;
for (i=0;i<8;i++)
{
dat<<=1;
dat|=DHT11_Read_Bit();//调用位函数
}
return dat;
}
//从DHT11读取一次数据,读取数据包模块
//temp:温度值(范围:0~50°)
//humi:湿度值(范围:20%~90%)
//返回值:0,正常;1,读取失败
u8 DHT11_Read_Data(u8 *temp,u8 *humi)
{
u8 buf[5];
u8 i;
DHT11_Rst();
if(DHT11_Check()==0)
{
for(i=0;i<5;i++)//读取40位数据
{
buf[i]=DHT11_Read_Byte();//调用字节函数
}
if((buf[0]+buf[1]+buf[2]+buf[3])==buf[4])
{
*humi=buf[0];
*temp=buf[2];
}
}
else return 1;
return 0;
}
//初始化DHT11的IO口 DQ 同时检测DHT11的存在
//返回1:不存在
//返回0:存在
u8 DHT11_Init(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE); //使能PG端口时钟
GPIO_InitStructure.GPIO_Pin = DT; //PG11端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_Init(GPIOA, &GPIO_InitStructure); //初始化Io口
GPIO_SetBits(GPIOA,DT); //PG11输出高
DHT11_Rst(); //复位DHT11
return DHT11_Check();//等待DHT11的回应
}
[相关代码](https://www.shangmayuan.com/a/ed3eaa42abfe427da69134c8.html)
HX711文件(AD转换器)(没用到)
#include "HX711.h"
#include "delay.h"
void Init_HX711pin(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB, ENABLE); //使能PF端口时钟
//HX711_SCK
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_0; //端口配置
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure); //根据设定参数初始化GPIOB
//HX711_DOUT
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_0); //初始化设置为o
}
//****************************************************
//读取HX711
//****************************************************
unsigned long HX711_Read(void) //增益128
{
unsigned long count; //储存输出值
unsigned char i;
//high--高电平 1 low--低电平 0
HX711_DOUT=1; //digitalWrite作用: DT=1;
delay_us(1);
HX711_SCK=0; //digitalWrite作用: SCK=0;
count=0;
while(HX711_DOUT); //当DT的值为1时,开始ad转换
for(i=0;i<24;i++)//24个脉冲,对应读取24位数值
{
HX711_SCK=1;
count=count<<1; //用于移位存储24位二进制数值
delay_us(1);
HX711_SCK=0; //digitalWrite作用: SCK=0;为下次脉冲做准备
if(HX711_DOUT)//若DT值为1,对应count输出值也为1
count++;
delay_us(1);
}
HX711_SCK=1; //再来一次上升沿 选择工作方式 128增益
count=count^0x800000;//第25个脉冲下降沿来时,转换数据//按位异或 不同则为1 0^0=0; 1^0=1;
//对应二进制 1000 0000 0000 0000 0000 0000 作用为将最高位取反,其他位保留原值
delay_us(1);
HX711_SCK=0; // SCK=0;
return(count);//返回传感器读取值
}
[详细](https://blog.csdn.net/weixin_45368394/article/details/106167426)
IIC文件(光照传感器就是iic通信)(首先肯定要有配置,起始信号和终止信号;主机发送一个数据,并且等待对方作出应答,即等待应答信号的到来;主机接受到数据,作出应答,即产生ack应答和不产生ack应答)
/****
本模拟IIC软件包包含了IIC操作的底层函数,如发送数据、接收数据、应答位发送。
------更新时间2018.2.23
调试经历:
仿照原始程序修改完后,进行测试,但是printf("\r\n%s",datatemp);就是不输出任何东西
后来,与例程比较后,发现在进行IIC_Config()中,是对GPIOA进行的初始化,不是GPIOB,但是为什么
软件没有报错呢?这种失误软件是检查不出来的,因为其语法并没有问题,需要自己认真检查。
****/
#include "IIC.h"
#include "stm32f10x_gpio.h"
#include "delay.h"
void IIC_Config(void)
{
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOB,ENABLE);
GPIO_InitStructure.GPIO_Pin=GPIO_Pin_7|GPIO_Pin_8;
GPIO_InitStructure.GPIO_Speed=GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode=GPIO_Mode_Out_PP; //推挽输出
GPIO_Init(GPIOB,&GPIO_InitStructure);
GPIO_SetBits(GPIOB,GPIO_Pin_7|GPIO_Pin_8); //将总线拉高释放总线
}
/***总线初始化:将总线拉高释放总线,发送启动信号前,要先初始化总线
即总线检测到总线空闲才开始发送启动信号****/
// void IIC_Init(void)
// {
// IIC_SDA=1;
// IIC_SCL=1;
// }
/***起始信号***/
void IIC_Start(void)
{
SDA_OUT() //设置SDA线为输出
//在开始数据传输前,先让SDA和SCL都拉高
IIC_SDA=1; //发送起始条件的数据信号,释放总线
delay_us(2);
IIC_SCL=1;
delay_us(5); //Tsu;STA:起始条件的建立时间大于4.7us。
IIC_SDA=0; //SDA由高变为低表示开始信号
delay_us(4); //起始条件的保持时间大于4us
IIC_SCL=0; //钳住IIC总线,准备发送或者接收数据
delay_us(2);
}
/***停止信号***/
void IIC_Stop(void)
{
SDA_OUT() //设置SDA线为输出
//IIC_SCL=0; //此句是调试BH1750时加,2018.03.03
IIC_SDA=0; //发送停止信号的数据信号
delay_us(2);
IIC_SCL=1; //发送停止信号的时钟信号
delay_us(5); //停止信号的建立时间大于4us
IIC_SDA=1; //发送停止信号
delay_us(4); //
}
/****等待应答信号到来****/
/*从器件进行应答信号
返回值:1 接收应答失败
0 接收应答成功
注意;此函数的返回值不会对下面的语句才生影响
*/
u8 IIC_Wait_Ack(void)
{
u8 ucErrorTime=0;
SDA_IN(); //SDA设置成输入
IIC_SDA=1;
delay_us(2);
IIC_SCL=1;
delay_us(2);
while(READ_SDA)
{
ucErrorTime++;
if(ucErrorTime>=250)
{
IIC_Stop();
return 1;
}
}
IIC_SCL=0;
return 0;
}
/****产生Ack应答****/
/****
主器件进行应答信号,产生应答
****/
void IIC_Ack(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=0; //主器件应答
delay_us(2);
IIC_SCL=1;
delay_us(4); //SCL高电平周期大于4us
IIC_SCL=0; //清时钟线,钳住IIC总线以便继续接收
delay_us(2);
}
/****不产生Ack应答****/
/****
主器件进行应答信号,不产生应答
****/
void IIC_NAck(void)
{
IIC_SCL=0;
SDA_OUT();
IIC_SDA=1; //主器件不应答
delay_us(2);
IIC_SCL=1;
delay_us(4); //SCL高电平周期大于4us
IIC_SCL=0; //清时钟线,钳住IIC总线以便继续接收
delay_us(2);
}
/****发送一个字节****/
/****
功能:将数据c发送出去,可以是地址,也可以是数据,发送完后等待应答,
****/
void IIC_Send_Byte(unsigned char c) //要传送的数据长度为8位
{
u8 i;
SDA_OUT();
for(i=0;i<8;i++)
{
if((c<<i)&0x80) IIC_SDA=1; //判断发送位
else IIC_SDA=0;
delay_us(2);
IIC_SCL=1; //拉高SCL,通知被控器开始接收数据位
delay_us(4); //保证SCL高电平周期大于4us
IIC_SCL=0; //拉低SCL,允许SDA传输下一位数据。因为只有在SCL=0时才允许SDA的状态发生变化
delay_us(2);
}
//以下四句是调试BH1750时添加的,2018.03.03
//特别注意;用方法三时,以下四句不可去掉,去掉后得到的数有问题
//用方法二时,以下四句需注释掉,否则也会有问题,至于原因暂时还不清楚。
// IIC_SDA=0;
// delay_us(2);
// IIC_SCL=1;
// delay_us(2);
IIC_SCL=0; //拉低SCL,为下次数据传输做好准备
delay_us(2);
}
/***接收一个字节***/
/***
功能:用来接收从器件传来的数据,ack为1时,发送Ack(产生应答);ack为0时,发送NAck(不产生应答)
注意:IIC读写数据时,高位在前,低位在后
***/
u8 IIC_Read_Byte(unsigned char ack)
{
unsigned char i,receive=0;
SDA_IN();
for(i=0;i<8;i++)
{
IIC_SCL=0; //置SCL为低,准备接收数据位
delay_us(5); //时钟低电平周期大于4.7us
IIC_SCL=1; //置SCL为高,使SDA上数据有效
delay_us(2);
receive=receive<<1;
if(READ_SDA) receive=receive+1; //读取SDA,把接收的数据位放入receve中,若此处写成IIC_SDA==1,会失败,思考原因?
delay_us(2);
}
if(!ack) IIC_NAck(); //发送NAck
else IIC_Ack(); //发送Ack
//IIC_SCL=0; //在此处有何用处???(猜测:为下次数据传输做好准备, //钳住IIC总线,准备发送或者接收数据)
//delay_us(2);
return receive;
}
[代码](https://www.cnblogs.com/dongxiaodong/p/9801684.html)
key文件(这里好像只有初始化,没有功能的实现)
#include "stm32f10x.h"
#include "key.h"
#include "sys.h"
#include "delay.h"
//ALIENTEK战舰STM32开发板
//按键驱动代码
//All rights reserved
//按键初始化函数
void KEY_Init(void) //IO初始化
{
GPIO_InitTypeDef GPIO_InitStructure;
//初始化KEY0-->GPIOA.13,KEY1-->GPIOA.15 上拉输入
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);//使能PORTA,PORTE时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_1|GPIO_Pin_2|GPIO_Pin_4|GPIO_Pin_5;//PE2~4
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //设置成上拉输入
GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOE2,3,4
}
lcd1602.c文件(IO配置,等待液晶准备好,写命令和写数据固定的应该,清屏,显示字符和显示数据,初始化)
#include "lcd1602.h"
#include "delay.h"
#include <string.h>
[GPIO配置代码](https://blog.csdn.net/fengtao612/article/details/5710990)
void GPIO_Configuration(void)//设置GPIO基本参数
{
GPIO_InitTypeDef GPIO_InitStructure;根据GPIO_InitStruct中指定的参数初始化外设GPIOx寄存器
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_GPIOB| RCC_APB2Periph_GPIOC,ENABLE);//使能PB,PD端口时钟
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_8|GPIO_Pin_6|GPIO_Pin_7|GPIO_Pin_11|GPIO_Pin_12;//设置的IO为pin8,pin6,pin7,pin11,pin12
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOA, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10|GPIO_Pin_11|GPIO_Pin_12|GPIO_Pin_13|GPIO_Pin_14|GPIO_Pin_15;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOB, &GPIO_InitStructure);
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_13;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //推挽输出
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //IO口速度为50MHz
GPIO_Init(GPIOC, &GPIO_InitStructure);
}
void DATA(u8 data)
{
D0=(data>>0)&0x01;
D1=(data>>1)&0x01;
D2=(data>>2)&0x01;
D3=(data>>3)&0x01;
D4=(data>>4)&0x01;
D5=(data>>5)&0x01;
D6=(data>>6)&0x01;
D7=(data>>7)&0x01;
}
/* 等待液晶准备好 */
void LCD1602_Wait_Ready(void)
{
u8 sta;
DATA(0xff);
LCD_RS_Clr();
LCD_RW_Set();
do
{
LCD_EN_Set();
delay_ms(5); //延时5ms,非常重要
sta = GPIO_ReadInputDataBit(GPIOA, GPIO_Pin_12);//读取状态字
LCD_EN_Clr();
}while(sta & 0x80);//bit7等于1表示液晶正忙,重复检测直到其等于0为止
}
[写命令和写数据](https://blog.csdn.net/rsd102/article/details/117044961)
/* 向LCD1602液晶写入一字节命令,cmd-待写入命令值 */
void LCD1602_Write_Cmd(u8 cmd)
{
LCD1602_Wait_Ready();
LCD_RS_Clr();
LCD_RW_Clr();
DATA(cmd);
LCD_EN_Set();
LCD_EN_Clr();
}
/* 向LCD1602液晶写入一字节数据,dat-待写入数据值 */
void LCD1602_Write_Dat(u8 dat)
{
LCD1602_Wait_Ready();
LCD_RS_Set();
LCD_RW_Clr();
DATA(dat);
LCD_EN_Set();
LCD_EN_Clr();
}
/* 清屏 */
void LCD1602_ClearScreen(void)
{
LCD1602_Write_Cmd(0x01);
}
[0x80可以看这里](https://blog.csdn.net/qq_38611124/article/details/90743900)
void LCD1602_Show_OneChar(u8 X,u8 Y,u8 DData)//被下面那个函数调用的,用来显示内容
{
if(Y==0)
{
LCD1602_Write_Cmd(X+0x80); //显示的位置 0x80是第一行第一个
LCD1602_Write_Dat(DData);//写LCD1602数据,DData是需要写入的数据
}
else if(Y==1)
{
LCD1602_Write_Cmd(X+0xc0);//0xc0是第二行第一个
LCD1602_Write_Dat(DData);
}
}
void LCD1602_Show_String(u8 X, u8 Y, u8 Length , u8 *DData)//字面上看是显示字符串,x y是现实位置。u8 Length应该是字符的长度,DData是内容,显示的是“T”“H”这些字符串
{
u8 ListLength,j;
ListLength = Length; //strlen是测字符串的长度
for(j=0;j<ListLength;j++)
{
LCD1602_Show_OneChar(X, Y, DData[j]); //显示单个字符
X++;
}
}
void LCD1602_Show_Num(u8 X, u8 Y,long n)//显示的是温度湿度这些的个十百三位的数据
{
u8 length=0,i,j,z, a[8]={0,0,0,0,0,0,0,0};
long nx;
if(n==0)
{
LCD1602_Show_OneChar(X,Y,'0');
return;
}
if(n<0)
{
LCD1602_Show_OneChar(X-1,Y,'-');
n=0-n;
}
nx=n;
for(j=0;j<8;j++)
{
if(nx>=1)
length++;
nx/=10;
}
z=length;
nx=n;
for(;length>0;length--)
{
a[length-1]=nx%10+0x30;
nx/=10;
}
for(i=0;i<z;i++)
{
LCD1602_Show_OneChar(X,Y,a[i]);
X++;
}
}
/* 初始化1602液晶 */
void LCD1602_Init(void)
{
LCD1602_Write_Cmd(0x38); //16*2显示,5*7点阵,8位数据口
LCD1602_Write_Cmd(0x38); //16*2显示,5*7点阵,8位数据口
LCD1602_Write_Cmd(0x38); //16*2显示,5*7点阵,8位数据口
LCD1602_Write_Cmd(0x0c); //开显示,光标关闭
LCD1602_Write_Cmd(0x06); //文字不动,地址自动+1
LCD1602_Write_Cmd(0x01); //清屏
}