物联网系列②——使用ESP8266与STM32进行物联网开发板设计
物联网系列②——使用ESP8266与STM32进行物联网开发板设计
- 一、设计目标
- 二、电路设计
- 1、原理图设计
- 2、电路板展示
- 三、目前实现的功能
- 四、代码编写
- 1、DHT11驱动代码
- 2、0.96寸OLED显示代码(包含驱动)
- 3、EEPROM驱动代码
- 4、与ESP8266串口通信(包含串口通信驱动)
- 5、DS1302驱动代码
- 6、读写FLASH
- 五、优化方向
一、设计目标
在ESP8266网络服务器的学习过程中,产生了制作一个ESP8266与STM32物联网开发板的想法。
该开发板具备以下功能:
- 主控芯片:STM32F103RCT6 ,具备CAN,I2C等丰富的外设,同时拥有256KB FLASH,便于代码的扩展。用作该电路的主控芯片,进行数据处理,实现对各种外设的控制。
- 物联网芯片:ESP12-F,作为云端与STM32通信的节点,负责数据传输。
- LED指示灯:4*LED指示灯,进行系统不同工作状态指示,如电源指示,系统开启指示,通讯指示等等。
- 0.96寸OLED:使用4线SPI通信,与按键结合进行系统功能设置.通过2.54MM母排与STM32F103RCT6连接。
- 3按键:3个按键接入STM32,功能分别为:返回键,向下键,OK键。3按键外接一个LED,模拟自带LED的按键模块效果。
- 温湿度模块:DHT11,进行温湿度采集,数据于OLED和云端显示
- 实时时钟:DS1302,用于离线状态的实时时钟显示,于OLED中显示。使用CR1220为其供电。
- EEPROM:记录系统运行数据,WIFI账号密码等,考虑记录温湿度数据,形成大数据
- 串口芯片:CH340,与电脑进行串口通信,同时也是STM32与ESP8266的程序下载端口,通过跳线帽选择下载程序的目标,分别对其进行程序下载
- CAN通信:使用TJA1050T和RJ45网口进行CAN通信
- 供电:通过TPS54231将12V转至5V,通过LM1117 将5V转3.3V 。使用DC 5.5*2.5mm接口供电,同时可使用Mico USB供电
二、电路设计
1、原理图设计
(1)供电:12V转5V,5V转3.3V,STM32供电
(2)STM32F103RCT6
(3)CAN
(4)DHT11
(5)0.96 OLED
(6)DS1302
(7)EEPROM
(8)程序下载接口
(9)3按键
(10)LED
(11)ESP12-F(红框处存在问题)
(12)CH340
这部分电路存在问题,电路图不在此处放出,仅介绍思路。要通过USB接口对STM32进行串口程序下载,需通过CH340芯片和三极管对boot0引脚进行电平操作。那是否可以通过ESP8266与STM32共用一个CH340芯片进行程序下载?通过排针和跳线帽选择要下载程序的芯片,这样成本不就降低了吗?
电路板打板回来焊接测试后,发现可以使用这个方案对STM32进行程序下载,但是ESP8266的程序总是下载不成功。经过一段时间的排查发现,在下载电路的设计上存在一个很大的问题!在设计时对ESP8266下载电路缺乏足够的认识,也没去看该芯片的规格书,以为将TX,RX接入CH340芯片即可,完全忽略了在下载程序时应该将GPIO0引脚拉低,再将芯片RST才能进入下载模式,这也导致了CH340电路缺少了对GPIO0的电路设计,直接导致了ESP8266无法进行程序下载。在不修改电路的前提下,要对ESP8266进行程序下载只能是通过外接TTL串口下载电路,然后手动将GPIO0电平拉低,再手动按下RST按键,才能成功地进行程序下载。电路板上CH340电路在设计上是完全错误的,未实现设计目标。ESP8266正确的下载电路应如下图所示(未包含STM32部分):
2、电路板展示
三、目前实现的功能
因平时时间有限,仅实现以下功能:
OLED驱动:
主界面:显示年月日时分秒等时间信息,显示当前温湿度
菜单界面:通过向下键移动光标,通过OK键对无线账号名称密码设置,时间设置,IO口电平控制,风扇控制等进行选择。
无线设置界面
时间设置界面
IO口控制界面
风扇控制界面
界面切换算法DS1302驱动:时间的获取和设置
DHT11驱动:温湿度数据获取
无线账号密码设置和时间设置算法,通过按键操作和OLED显示屏显示完成此功能,此部分内容更多的是算法层面的代码编写
IO口电平控制:与4点算法类似,通过按键设置IO口的电平状态,并反馈于OLED界面
风扇控制:通过外接继电器,通过一个IO口控制继电器的开关,继电器接风扇,从而实现IO口对风扇开关的控制。结合了DHT11温湿度传感器,可设置温度高于多少度时风扇自动开启,如温度高于25°C时风扇自动开启,低于25°C时风扇便关闭了,类似智能家居的联动功能
EEPROM驱动:实现对EEPROM数据的写入和读取
CAN通信:实现两设备间数据的发送和获取
串口通信:实现与ESP8266的串口通信
10.FLASH读写:实现对FLASH的读写,在非程序区域进行读写,实现类似EEPROM功能
四、代码编写
1、DHT11驱动代码
#include "stm32f10x.h" //STM32器件寄存器定义头文件,必须包含
#include "Delay.h"
#include "DHT11.h"u8 HUM_DATA_H_TEST,HUM_DATA_L_TEST,TEMP_DATA_H_TEST,TEMP_DATA_L_TEST,CHECK_DATA_TEST; //用于数据校验
u8 HUM_DATA_H,HUM_DATA_L,TEMP_DATA_H,TEMP_DATA_L,CHECK_DATA;//***********************************************************************
// DMT11数据引脚配置为输出
//***********************************************************************
void DHT11_GPIO_OUT(void)
{GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = DHT11_Pin; //使用GPIOC_12引脚GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //配置为推挽输出GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(DHT11_Pin_Port, &GPIO_InitStructure); //相关的GPIO口初始化GPIO_SetBits(DHT11_Pin_Port, DHT11_Pin);
}
//***********************************************************************
// DMT11数据引脚配置为输入
//***********************************************************************
void DHT11_GPIO_IN(void)
{GPIO_InitTypeDef GPIO_InitStructure;GPIO_InitStructure.GPIO_Pin = DHT11_Pin; //使用GPIOC_12引脚 GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //配置为输入GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; GPIO_Init(DHT11_Pin_Port, &GPIO_InitStructure); //相关的GPIO口初始化
}
//***********************************************************************
// DMT11 8位数据读取函数
//***********************************************************************
u8 DHT11_DATA_8bit(void)
{ u32 count=5000; //防呆u8 data=0,i;for(i=0;i<8;i++){count =5000;while((!DHT11_DATA)&&(count>0)) {count--;} //等待数据引脚拉高delay_us(30); //26-28us表示为0,70us表示为1if(DHT11_DATA) //如果此时依然读取到高电平则表示该值为1{data = (data<<1)+1; //左移一位 }else //如果此时读到低电平{data<<=1; //左移一位}count =5000;while((DHT11_DATA)&&(count>0)) count--; //等待数据引脚拉低,即一位数据读取完毕 }return data;
}
//***********************************************************************
// DMT11数据读取函数
//***********************************************************************
void DHT11_DATA_READ(void)
{ DHT11_GPIO_OUT(); //设置为输出DHT11_DATA_CLR; //拉低数据线,发出开始标志delay_mms(20); //总线拉低后必须至少18ms,确保DHT11能检测到起始信号DHT11_DATA_SET; //拉高并进行延时等待delay_us(20); //延迟20-40us,等待响应信号DHT11_GPIO_IN(); //切换为输入模式delay_us(180);//等待80us的响应时间结束//等待80us的拉高时间结束//开始接收数据HUM_DATA_H_TEST = DHT11_DATA_8bit();HUM_DATA_L_TEST = DHT11_DATA_8bit();TEMP_DATA_H_TEST = DHT11_DATA_8bit();TEMP_DATA_L_TEST = DHT11_DATA_8bit();CHECK_DATA_TEST = DHT11_DATA_8bit();DHT11_GPIO_OUT();//数据校验CHECK_DATA = (HUM_DATA_H_TEST + HUM_DATA_L_TEST + TEMP_DATA_H_TEST + TEMP_DATA_L_TEST);if(CHECK_DATA == CHECK_DATA_TEST){HUM_DATA_H = HUM_DATA_H_TEST;HUM_DATA_L = HUM_DATA_L_TEST;TEMP_DATA_H = TEMP_DATA_H_TEST;TEMP_DATA_L = TEMP_DATA_L_TEST;}
}
#ifndef __DHT11_H
#define __DHT11_H
#include "user_define.h"
#include "Delay.h"
/*温湿度传感器接口定义*/#define DHT11_Pin GPIO_Pin_11
#define DHT11_Pin_Port GPIOB
#define RCC_DHT11 RCC_APB2Periph_GPIOB
#define DHT11_DATA_CLR GPIO_ResetBits(DHT11_Pin_Port, DHT11_Pin) //DATA置低
#define DHT11_DATA_SET GPIO_SetBits(DHT11_Pin_Port, DHT11_Pin) //DATA置高
#define DHT11_DATA GPIO_ReadInputDataBit(DHT11_Pin_Port, DHT11_Pin) //DATA输入extern u8 HUM_DATA_H;
extern u8 HUM_DATA_L;
extern u8 TEMP_DATA_H;
extern u8 TEMP_DATA_L;
extern u8 CHECK_DATA;void DHT11_DATA_READ(void);
#endif
2、0.96寸OLED显示代码(包含驱动)
#include "oled.h"
#include "user_config.h"
#include "bmp.h" //图库
#include "oledfont.h" //字库char WIFI_NAME_Enter[10]={0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A};//输入密码存储,默认8个星号
char WIFI_KEY_Enter[10]={0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A};//输入密码存储,默认8个星号
char FAN_TEMP_Enter[5]={0x2A,0x2A,0x2A};//输入温度数据存储,默认3个星号
u8 time_set[13]={0x30,0x30,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,0x2A,}; //秒十位,秒个位,分十位,分个位,时十位,时个位,日十位,日个位,月十位,月个位,周,年十位,年个位
u8 time_set1[7];//秒,分,时,日,月,周,年
u8 FAN_STATE_Flag=0;//风扇状态标志位
u8 FAN_TEMP_Control_Flag=0;//风扇温度控制标志位
char sec1,min1,hour1,year1,mon1,dat1;//上一次的时间数值
#if OLED_MODE==1
/*** @brief 向SSD1106写入一个字节* @param dat:要写入的数据/命令 cmd:数据/命令标志 0,表示命令;1,表示数据* @retval None*/
void OLED_WR_Byte(uint8_t dat,uint8_t cmd)
{DATAOUT(dat); if(cmd)OLED_DC_Set();else OLED_DC_Clr(); OLED_CS_Clr();OLED_WR_Clr(); OLED_WR_Set();OLED_CS_Set(); OLED_DC_Set();
}
#else/*** @brief 向SSD1106写入一个字节* @param dat:要写入的数据/命令 cmd:数据/命令标志 0,表示命令;1,表示数据;* @retval None*/
void OLED_WR_Byte(uint8_t dat,uint8_t cmd)
{ uint8_t i; if(cmd)OLED_DC_Set();else OLED_DC_Clr(); for(i=0;i<8;i++){ OLED_SCLK_Clr();if(dat&0x80)OLED_SDIN_Set();else OLED_SDIN_Clr();OLED_SCLK_Set();dat<<=1; } OLED_DC_Set();
}
#endif/*** @brief 清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样* @param None* @retval None*/
void OLED_Set_Pos(unsigned char x, unsigned char y)
{ OLED_WR_Byte(0xb0+y,OLED_CMD);OLED_WR_Byte(((x&0xf0)>>4)|0x10,OLED_CMD);OLED_WR_Byte((x&0x0f)|0x01,OLED_CMD);
} /*** @brief 开启OLED显示* @param None* @retval None*/
void OLED_Display_On(void)
{OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令OLED_WR_Byte(0X14,OLED_CMD); //DCDC ONOLED_WR_Byte(0XAF,OLED_CMD); //DISPLAY ON
}/*** @brief 关闭OLED显示 * @param None* @retval None*/
void OLED_Display_Off(void)
{OLED_WR_Byte(0X8D,OLED_CMD); //SET DCDC命令OLED_WR_Byte(0X10,OLED_CMD); //DCDC OFFOLED_WR_Byte(0XAE,OLED_CMD); //DISPLAY OFF
} /*** @brief 清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样* @param None* @retval None*/
void OLED_Clear(void)
{ uint8_t 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); } //更新显示
}/*** @brief 在指定位置显示一个字符,包括部分字符* @param x:0~127 y:0~63 mode:0,反白显示 1,正常显示 size:选择字体 16/12 * @retval None*/
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr)
{ unsigned char c=0,i=0; c=chr-' '; //得到偏移后的值 if(x>Max_Column-1){x=x;y=y+2;}if(SIZE==16){OLED_Set_Pos(x,y); for(i=0;i<8;i++)OLED_WR_Byte(D8X16[c*16+i],OLED_DATA);OLED_Set_Pos(x,y+1);for(i=0;i<8;i++)OLED_WR_Byte(D8X16[c*16+i+8],OLED_DATA);}else if(SIZE==12){ OLED_Set_Pos(x,y); for(i=0;i<6;i++)OLED_WR_Byte(D12X12[c][i],OLED_DATA);OLED_Set_Pos(x,y+1);for(i=0;i<6;i++)OLED_WR_Byte(D12X12[c][i+6],OLED_DATA);}else if(SIZE==24){ OLED_Set_Pos(x,y); for(i=0;i<12;i++)OLED_WR_Byte(D24X24[c][i],OLED_DATA);OLED_Set_Pos(x,y+1);for(i=0;i<12;i++)OLED_WR_Byte(D24X24[c][i+12],OLED_DATA);}else if(SIZE==8){OLED_Set_Pos(x,y);for(i=0;i<8;i++){OLED_WR_Byte(D8X8[c][i],OLED_DATA);}}else if(SIZE==6){OLED_Set_Pos(x,y+1);for(i=0;i<6;i++){OLED_WR_Byte(D6X8[c][i],OLED_DATA);}}
}
/*** @brief 在指定位置显示一个字符,可调节字符大小* @param x:0~127 y:0~63 mode:0,反白显示 1,正常显示 size:选择字体 16/12 * @retval None*/
void OLED_ShowChar_Adjust(uint8_t size,uint8_t x,uint8_t y,uint8_t chr)
{ unsigned char c=0,i=0; c=chr-' '; //得到偏移后的值 if(x>Max_Column-1){x=x-127;y=y+2;}if(size==24){ OLED_Set_Pos(x,y); for(i=0;i<12;i++)OLED_WR_Byte(D24X24[c][i],OLED_DATA);OLED_Set_Pos(x,y+1);for(i=0;i<12;i++)OLED_WR_Byte(D24X24[c][i+12],OLED_DATA);}else if(size==16){OLED_Set_Pos(x,y); for(i=0;i<8;i++)OLED_WR_Byte(D8X16[c*16+i],OLED_DATA);OLED_Set_Pos(x,y+1);for(i=0;i<8;i++)OLED_WR_Byte(D8X16[c*16+i+8],OLED_DATA);}else if(size==12){ OLED_Set_Pos(x,y); for(i=0;i<6;i++)OLED_WR_Byte(D12X12[c][i],OLED_DATA);OLED_Set_Pos(x,y+1);for(i=0;i<6;i++)OLED_WR_Byte(D12X12[c][i+6],OLED_DATA);}else if(size==8){OLED_Set_Pos(x,y);for(i=0;i<8;i++){OLED_WR_Byte(D8X8[c][i],OLED_DATA);}}else if(size==6){OLED_Set_Pos(x,y+1);for(i=0;i<6;i++){OLED_WR_Byte(D6X8[c][i],OLED_DATA);}}
}
/*** @brief m^n函数* @param None* @retval None*/
uint32_t oled_pow(uint8_t m,uint8_t n)
{uint32_t result=1; while(n--)result*=m; return result;
} /*** @brief 显示2个数字* @param x,y :起点坐标* len :数字的位数,即显示几位有效数字* size:字体大小* mode:模式 0,填充模式;1,叠加模式* num:数值(0~4294967295);* @retval None*/
void OLED_ShowNum(uint8_t x,uint8_t y,uint32_t num,uint8_t len,uint8_t size)
{ uint8_t t,temp;uint8_t 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+(size/2)*t,y,' ');continue;}else enshow=1; }OLED_ShowChar(x+(size/2)*t,y,temp+'0'); }
} /*** @brief 显示一个字符号串* @param * @retval None*/
void OLED_ShowString(uint8_t x,uint8_t y,char *chr)
{unsigned char j=0;while(chr[j]!='\0'){ OLED_ShowChar(x,y,chr[j]);x+=8;if(x>120){x=0;y+=2;}j++;}
}/*** @brief 显示显示BMP图片* @param 显示显示BMP图片128×64起始点坐标(x,y),x的范围0~127,y为页的范围0~7* @retval None*/
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); }}
} /*** @brief 初始化SSD1306* @param None* @retval None*/
void OLED_InitConfig(void)
{ OLED_RST_Set();delay_mms(100);OLED_RST_Clr();delay_mms(100);OLED_RST_Set(); OLED_WR_Byte(0xAE,OLED_CMD);//--turn off oled panelOLED_WR_Byte(0x00,OLED_CMD);//---set low column addressOLED_WR_Byte(0x10,OLED_CMD);//---set high column addressOLED_WR_Byte(0x40,OLED_CMD);//--set start line address Set Mapping RAM Display Start Line (0x00~0x3F)OLED_WR_Byte(0x81,OLED_CMD);//--set contrast control registerOLED_WR_Byte(0xCF,OLED_CMD);// Set SEG Output Current BrightnessOLED_WR_Byte(0xA1,OLED_CMD);//--Set SEG/Column Mapping 0xa0左右反置 0xa1正常OLED_WR_Byte(0xC8,OLED_CMD);//Set COM/Row Scan Direction 0xc0上下反置 0xc8正常OLED_WR_Byte(0xA6,OLED_CMD);//--set normal displayOLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64)OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 dutyOLED_WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F)OLED_WR_Byte(0x00,OLED_CMD);//-not offsetOLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequencyOLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/SecOLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge periodOLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 ClockOLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configurationOLED_WR_Byte(0x12,OLED_CMD);OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomhOLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect LevelOLED_WR_Byte(0x20,OLED_CMD);//-Set Page Addressing Mode (0x00/0x01/0x02)OLED_WR_Byte(0x02,OLED_CMD);//OLED_WR_Byte(0x8D,OLED_CMD);//--set Charge Pump enable/disableOLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disableOLED_WR_Byte(0xA4,OLED_CMD);// Disable Entire Display On (0xa4/0xa5)OLED_WR_Byte(0xA6,OLED_CMD);// Disable Inverse Display On (0xa6/a7) OLED_WR_Byte(0xAF,OLED_CMD);//--turn on oled panelOLED_WR_Byte(0xAF,OLED_CMD); /*display ON*/ OLED_Clear();OLED_Set_Pos(0,0);
} /*****************************************************/
/* 以下为IOT OLED显示算法部分 */
/*****************************************************/
//系统开机界面
void OLED_StartDesk(void)
{OLED_Clear();OLED_ShowString(16, 0, "IOT Loading.");OLED_DrawBMP(40,2,88,8,logo);delay_s(3);OLED_ShowString(16, 0, "IOT Loading..");delay_s(3);OLED_ShowString(16, 0, "IOT Loading...");delay_s(2);OLED_Clear();
}
//无线信息获取界面
void OLED_WIFI(uint8_t shift)
{OLED_ShowString(19, 0, "Information");OLED_ShowString(20, 2, "WIFI Name");OLED_ShowString(20, 4, "WIFI Password");OLED_ShowString(20, 6, "WIFI IP");if(shift%3==1){OLED_ShowString(0, 4, "->");}else if(shift%3==2){OLED_ShowString(0, 6, "->");}else if(shift%3==0){OLED_ShowString(0, 2, "->");}
}
//无线名称显示
void OLED_WIFI_Name(u16 *Snum)
{u8 i=0;u8 length=0;u32 temp_data =0;OLED_ShowString(27, 0, "WIFI NAME");if(WIFI_Name_Length*8<128)//如果未超出1行显示空间{length=(128-WIFI_Name_Length*8)/2;//居中显示for(i=0;i<WIFI_Name_Length;i++)//显示无线名称{ temp_data =Snum[i]; OLED_ShowChar(length+i*8,4,temp_data);}}else//超出1行显示区域{for(i=0;i<WIFI_Name_Length;i++)//显示无线名称{ temp_data =Snum[i]; OLED_ShowChar(i*8,4,temp_data);}}
}
//无线密码显示
void OLED_WIFI_Password(u16 *Snum)
{u8 i=0;u8 length=0;u32 temp_data =0;OLED_ShowString(27, 0, "WIFI Key");if(WIFI_Password_Length*8<128)//如果未超出1行显示空间{length=(128-WIFI_Password_Length*8)/2;//居中显示for(i=0;i<WIFI_Password_Length;i++)//显示无线名称{ temp_data =Snum[i]; OLED_ShowChar(length+i*8,4,temp_data);}}else//超出1行显示区域{for(i=0;i<WIFI_Password_Length;i++)//显示无线名称{ temp_data =Snum[i]; OLED_ShowChar(i*8,4,temp_data);}}
}
//无线IP显示
void OLED_WIFI_IP(u16 *Snum)
{u8 i=0;u8 length=0;u32 temp_data =0;OLED_ShowString(27, 0, "WIFI IP");if(WIFI_IP_Length*8<128)//如果未超出1行显示空间{length=(128-WIFI_IP_Length*8)/2;//居中显示for(i=0;i<WIFI_IP_Length;i++)//显示无线名称{ temp_data =Snum[i]; OLED_ShowChar(length+i*8,4,temp_data);}}else//超出1行显示区域{for(i=0;i<WIFI_Password_Length;i++)//显示无线名称{ temp_data =Snum[i]; OLED_ShowChar(i*8,4,temp_data);}}
}
//用户设置界面
void OLED_AskDesk(uint8_t shift)
{OLED_ShowString(36, 0, "Setting");OLED_ShowString(30, 2, "Cread WIFI");OLED_ShowString(30, 4, "Connect WIFI");//OLED_ShowString(30, 6, "Send Data");if((shift+1)%2==1){OLED_ShowString(10, 2, "->");}else if((shift+1)%2==0){OLED_ShowString(10, 4, "->");}
}
//用户创建一个无线界面
void OLED_Cread_WIFI(uint8_t shift)
{OLED_ShowString(24, 0, "Cread WIFI");OLED_ShowString(30, 2, "WIFI Name");OLED_ShowString(30, 4, "WIFI Key");OLED_ShowString(30, 6, "Send Data");if((shift+1)%3==1){OLED_ShowString(10, 2, "->");}else if((shift+1)%3==0){OLED_ShowString(10, 6, "->");}else if((shift+1)%3==2){OLED_ShowString(10, 4, "->");}
}
//用户设置无线名称界面
void OLED_Cread_WIFI_NAME(uint8_t shift1,uint8_t shift2)//shift1向下,shift2确认后选择数字
{char temp[1];//u8 LAST=0;//之前shift2的数值OLED_ShowString(28,0, " WIFI NAME");OLED_ShowString(32, 4, WIFI_NAME_Enter);OLED_ShowString(32+shift1*8, 4, "_");if(shift2!=0){if(shift2==10){temp[0]=0x30;OLED_ShowString(32+shift1*8, 4, "0");}else{temp[0]=shift2+0x30;OLED_ShowString(32+shift1*8, 4, temp);}if(Enter_Over_Flag==1)//如果确认输入{WIFI_NAME_Enter[shift1]=temp[0];//存储数据Enter_Over_Flag=0;//清空标志位}}
}
//用户设置无线密码界面
void OLED_Cread_WIFI_Password(uint8_t shift1,uint8_t shift2)//shift1向下,shift2确认后选择数字
{char temp[1];//u8 LAST=0;//之前shift2的数值OLED_ShowString(28,0, " WIFI KEY");OLED_ShowString(32, 4, WIFI_KEY_Enter);OLED_ShowString(32+shift1*8, 4, "_");if(shift2!=0){if(shift2==10){temp[0]=0x30;OLED_ShowString(32+shift1*8, 4, "0");}else{temp[0]=shift2+0x30;OLED_ShowString(32+shift1*8, 4, temp);}if(Enter_Over_Flag==1)//如果确认输入{WIFI_KEY_Enter[shift1]=temp[0];//存储数据Enter_Over_Flag=0;//清空标志位}}
}
void OLED_Send_WIFI_DATA(uint8_t shift)//发送无线命令显示界面
{u8 i=0,j=0,h=0;for(i=0;i<8;i++){if(WIFI_NAME_Enter[i]!=0x2A){j++;}if(WIFI_KEY_Enter[i]!=0x2A){h++;}}if(j==8&&h==8){//ESP8266_SendData(Send_WIFI_Data,0x00,0x00);//发送无线数据//OLED_ShowString(28, 0, "WIFI DATA");OLED_ShowString(20, 0, "SEND DATA?");OLED_ShowString(28, 4, "YSE");OLED_ShowString(76, 4, "NO");if((shift+1)%2==1){OLED_ShowString(12, 4, "->");}else if((shift+1)%2==0){OLED_ShowString(60, 4, "->");}}else{OLED_ShowString(28, 0, "WIFI DATA");OLED_ShowString(28, 4, "DATA Error");}}
void OLED_Send_DATA(uint8_t shift)//发送命令显示界面
{u8 i;OLED_Clear();OLED_DrawBMP(40,2,88,8,logo);if(shift==2){OLED_ShowString(8, 0, "DATA Sending.");for(i=0;i<8;i++){ESP8266_SendData(Send_WIFI_Name,0x00,WIFI_NAME_Enter[i]);//发送无线名称ESP8266_SendData(Send_WIFI_Key,0x00,WIFI_KEY_Enter[i]);//发送无线密码}}else if(shift==1){OLED_ShowString(8, 0, "DATA Sending..");}else if(shift==0){OLED_ShowString(8, 0, "DATA Sending...");}
}
//主界面显示
void OLED_DESK(void)
{OLED_ShowString(48, 0,"DESK");OLED_time();//时间OLED_Temp_Hum();//温度,湿度
}
//时钟显示
void OLED_time(void)
{char sec,min,hour,year,mon,dat;char data1,data2;//十位,个位hour=time[2];//小时min=time[1];//分sec=time[0];//秒year=time[6];//年mon=time[4];//月dat=time[3];//日if((hour1>=10&&hour<10)||(min1>=10&&min<10)||(sec1>=10&&sec<10)||(mon1>=10&&mon<10)||(dat1>=10&&dat<10)){OLED_Clear();//屏幕刷新}hour1=hour;min1=min;sec1=sec;year1=year;mon1=mon;dat1=dat;if(hour<10)//个位数{data1=hour+0x30;OLED_ShowString(32, 2,"0");OLED_ShowString(40, 2,&data1);}else{data1=hour/10;//十位data1=data1+0x30;OLED_ShowString(32, 2,&data1);data2=hour%10;//个位data2=data2+0x30;OLED_ShowString(40, 2,&data2);}if(min<10)//个位数{data1=min+0x30;OLED_ShowString(56, 2,"0");OLED_ShowString(64, 2,&data1);}else{data1=min/10;//十位data1=data1+0x30;OLED_ShowString(56, 2,&data1);data2=min%10;//个位data2=data2+0x30;OLED_ShowString(64, 2,&data2);}if(sec<10)//个位数{data1=sec+0x30;OLED_ShowString(80, 2,"0");OLED_ShowString(88, 2,&data1);}else{data1=sec/10;//十位data1=data1+0x30;OLED_ShowString(80, 2,&data1);data2=sec%10;//个位data2=data2+0x30;OLED_ShowString(88, 2,&data2);}OLED_ShowString(48, 2,":");OLED_ShowString(72, 2,":");//年月日显示data2=year/10+0x30;//十位data1=year%10+0x30;//个位OLED_ShowString(24, 4,"20");OLED_ShowString(40, 4,&data2);OLED_ShowString(48, 4,&data1);OLED_ShowString(56, 4,".");data2=mon/10+0x30;//十位data1=mon%10+0x30;//个位OLED_ShowString(64, 4,&data2);OLED_ShowString(72, 4,&data1);OLED_ShowString(80, 4,".");data2=dat/10+0x30;//十位data1=dat%10+0x30;//个位OLED_ShowString(88, 4,&data2);OLED_ShowString(96, 4,&data1);
}
//显示温度,湿度
void OLED_Temp_Hum(void)
{u8 i;char temp_char[5]={0},Hum_char[3]={0};char temp[10]={0x00,0x00,0x0C,0x12,0x12,0x0C,0x00,0x00};//“°”u16 temp_t= TEMP_DATA_H%10;u16 hum_t = HUM_DATA_H%10;temp_char[0]=TEMP_DATA_H/10+0x30;temp_char[1]=temp_t+0x30;temp_char[2]='.';temp_char[3]=TEMP_DATA_L+0x30;OLED_ShowString(10,6,temp_char);//"°"OLED_Set_Pos(42,6);for(i=0;i<8;i++){OLED_WR_Byte(temp[i],OLED_DATA);}OLED_ShowString(48,6,"C");Hum_char[0] = HUM_DATA_H/10+0x30;Hum_char[1] = hum_t+0x30;OLED_ShowString(100,6,Hum_char);OLED_ShowString(116,6,"%");
}
//菜单界面
void OLED_MENU(uint8_t shift)
{OLED_ShowString(48, 0, "MENU");if((shift+1)%4<=3&&(shift+1)%4>0){OLED_ShowString(30, 2, "WIFI SET");//设置无线OLED_ShowString(30, 4, "Time SET");//设置时间OLED_ShowString(30, 6, "IO Contron");//引脚控制if((shift+1)%4==1){OLED_ShowString(10, 2, "->");}else if((shift+1)%4==3){OLED_ShowString(10, 6, "->");}else if((shift+1)%4==2){OLED_ShowString(10, 4, "->");}}else{OLED_ShowString(30, 2, "FAN CONTROL");//设置风扇if((shift+1)%4==0){OLED_ShowString(10, 2, "->");}}
}
//时间设置界面
void OLED_Time_Set(uint8_t shift1,uint8_t shift2)//shift1向下,shift2确认后选择数字
{char temp[1];char data1,data2;//十位,个位OLED_ShowString(32, 0,"Time Set");OLED_ShowString(62, 6,"SET");data1=time_set[4];data2=time_set[5];OLED_ShowString(32, 2,&data1);OLED_ShowString(40, 2,&data2);//hourdata1=time_set[2];data2=time_set[3];OLED_ShowString(56, 2,&data1);OLED_ShowString(64, 2,&data2);//mindata1=time_set[0];data2=time_set[1];OLED_ShowString(80, 2,&data1);OLED_ShowString(88, 2,&data2);//secOLED_ShowString(48, 2,":");OLED_ShowString(72, 2,":");//年月日显示OLED_ShowString(24, 4,"20");data1=time_set[11];data2=time_set[12];OLED_ShowString(40, 4,&data1);OLED_ShowString(48, 4,&data2);//yearOLED_ShowString(56, 4,".");data1=time_set[8];data2=time_set[9];OLED_ShowString(64, 4,&data1);OLED_ShowString(72, 4,&data2);//monOLED_ShowString(80, 4,".");data1=time_set[6];data2=time_set[7];OLED_ShowString(88, 4,&data1);OLED_ShowString(96, 4,&data2);//daydata1=time_set[10];OLED_ShowString(116, 4,&data1);//weekif(shift1==0) OLED_ShowString(32, 2, "_");else if(shift1==1) OLED_ShowString(40, 2, "_");else if(shift1==2) OLED_ShowString(56, 2, "_");else if(shift1==3) OLED_ShowString(64, 2, "_");else if(shift1==4) OLED_ShowString(40, 4, "_");else if(shift1==5) OLED_ShowString(48, 4, "_");else if(shift1==6) OLED_ShowString(64, 4, "_");else if(shift1==7) OLED_ShowString(72, 4, "_");else if(shift1==8) OLED_ShowString(88, 4, "_");else if(shift1==9) OLED_ShowString(96, 4, "_");else if(shift1==10) OLED_ShowString(116, 4, "_");else if(shift1==11) OLED_ShowString(46, 6, "->");if(shift2!=0){if(shift2==10){temp[0]=0x30;if(shift1==0) OLED_ShowString(32, 2, "0");else if(shift1==1) OLED_ShowString(40, 2, "0");else if(shift1==2) OLED_ShowString(56, 2, "0");else if(shift1==3) OLED_ShowString(64, 2, "0");else if(shift1==4) OLED_ShowString(40, 4, "0");else if(shift1==5) OLED_ShowString(48, 4, "0");else if(shift1==6) OLED_ShowString(64, 4, "0");else if(shift1==7) OLED_ShowString(72, 4, "0");else if(shift1==8) OLED_ShowString(88, 4, "0");else if(shift1==9) OLED_ShowString(96, 4, "0");else if(shift1==10) OLED_ShowString(116, 4, "0");}else{temp[0]=shift2+0x30;if(shift1==0) OLED_ShowString(32, 2, temp);else if(shift1==1) OLED_ShowString(40, 2, temp);else if(shift1==2) OLED_ShowString(56, 2, temp);else if(shift1==3) OLED_ShowString(64, 2, temp);else if(shift1==4) OLED_ShowString(40, 4, temp);else if(shift1==5) OLED_ShowString(48, 4, temp);else if(shift1==6) OLED_ShowString(64, 4, temp);else if(shift1==7) OLED_ShowString(72, 4, temp);else if(shift1==8) OLED_ShowString(88, 4, temp);else if(shift1==9) OLED_ShowString(96, 4, temp);else if(shift1==10) OLED_ShowString(116, 4, temp);}if(Enter_Over_Flag==1)//如果确认输入{if(shift1==0) time_set[4]=temp[0];//存储数据else if(shift1==1) time_set[5]=temp[0];//存储数据else if(shift1==2) time_set[2]=temp[0];//存储数据else if(shift1==3) time_set[3]=temp[0];//存储数据else if(shift1==4) time_set[11]=temp[0];//存储数据else if(shift1==5) time_set[12]=temp[0];//存储数据else if(shift1==6) time_set[8]=temp[0];//存储数据else if(shift1==7) time_set[9]=temp[0];//存储数据else if(shift1==8) time_set[6]=temp[0];//存储数据else if(shift1==9) time_set[7]=temp[0];//存储数据else if(shift1==10) time_set[10]=temp[0];//存储数据Enter_Over_Flag=0;//清空标志位}}
}
//时钟设置确认界面
void OLED_Time_Set_Check(void)
{u8 i,j=0;u8 Addr=0x80;for(i=0;i<13;i++){if(time_set[i]!=0x2A){j++;}}if(j==13)//所有数据均已设置好{time_set1[0]=0x00;//秒time_set1[1]=(time_set[2]-0x30)*16+(time_set[3]-0x30);//分time_set1[2]=(time_set[4]-0x30)*16+(time_set[5]-0x30);//时time_set1[3]=(time_set[6]-0x30)*16+(time_set[7]-0x30);//日time_set1[4]=(time_set[8]-0x30)*16+(time_set[9]-0x30);//月time_set1[5]=(time_set[10]-0x30)*16;//周time_set1[6]=(time_set[11]-0x30)*16+(time_set[12]-0x30);//年Write_Data(0x00,0x8e); //关闭写保护for(i = 0;i<7;i++){Write_Data(time_set1[i],Addr); Addr+=2;}Write_Data(0x80,0x8e); //开启写保护OLED_ShowString(20, 2, "SET Succeed");}else{OLED_ShowString(28, 2, "DATA Error");}
}
//IO口设置列表
void IO_Control_Menu(uint8_t shift)
{OLED_ShowString(24, 0, "IO Control");OLED_ShowString(30, 2, "PC13");//设置PC13OLED_ShowString(30, 4, "PC12");//设置PC12OLED_ShowString(30, 6, "PB15");//设置PB15if((shift+1)%3==1){OLED_ShowString(10, 2, "->");}else if((shift+1)%3==0){OLED_ShowString(10, 6, "->");}else if((shift+1)%3==2){OLED_ShowString(10, 4, "->");}if(GPIO_ReadOutputDataBit(CONTROL_Port1,CONTROL_PinC13)==0){OLED_ShowString(84, 2, "OFF");}else{OLED_ShowString(84, 2, "ON");}if(GPIO_ReadOutputDataBit(CONTROL_Port1,CONTROL_PinC12)==0){OLED_ShowString(84, 4, "OFF");}else{OLED_ShowString(84, 4, "ON");}if(GPIO_ReadOutputDataBit(CONTROL_Port2,CONTROL_PinB15)==0){OLED_ShowString(84, 6, "OFF");}else{OLED_ShowString(90, 6, "ON");}
}
//IO口设置
void IO_Control(uint8_t shift1,uint8_t shift2)
{OLED_ShowString(24, 0, "IO Control");OLED_ShowString(28, 4, "ON");OLED_ShowString(76, 4, "OFF");if((shift1+1)%3==1){OLED_ShowString(48, 2, "PC13");}else if((shift1+1)%3==0){OLED_ShowString(48, 2, "PB15");}else if((shift1+1)%3==2){OLED_ShowString(48, 2, "PC12");}if((shift2+1)%2==1){OLED_ShowString(12, 4, "->");}else if((shift2+1)%2==0){OLED_ShowString(60, 4, "->");}
}
void IO_Control_Data_Set(uint8_t shift1,uint8_t shift2)
{OLED_ShowString(20, 2, "SET Succeed");if((shift2+1)%2==1)//ON{if((shift1+1)%3==1){CONTROL_PinC13_ON;}else if((shift1+1)%3==0){CONTROL_PinB15_ON;}else if((shift1+1)%3==2){CONTROL_PinC12_ON;}}else if((shift2+1)%2==0)//OFF{if((shift1+1)%3==1){CONTROL_PinC13_OFF;}else if((shift1+1)%3==0){CONTROL_PinB15_OFF;}else if((shift1+1)%3==2){CONTROL_PinC12_OFF;}}
}
//风扇设置
void Fan_Control(uint8_t shift)
{OLED_ShowString(20, 0, "FAN Control");OLED_ShowString(30, 2, "ON/OFF");OLED_ShowString(30, 4, "Temp");if((shift+1)%2==1){OLED_ShowString(12, 2, "->");}else if((shift+1)%2==0){OLED_ShowString(12, 4, "->");}
}
void Fan_Control_ON_OFF(uint8_t shift)
{OLED_ShowString(20, 0, "FAN Control");OLED_ShowString(28, 4, "ON");OLED_ShowString(76, 4, "OFF");if((shift+1)%2==1){OLED_ShowString(12, 4, "->");}else if((shift+1)%2==0){OLED_ShowString(60, 4, "->");}
}void Fan_Control_ON_OFF_Set(uint8_t shift)
{OLED_ShowString(20, 2, "SET Succeed");if((shift+1)%2==1)//ON{FAN_CONTROL_Pin_ON;FAN_STATE_Flag=1;//风扇状态为1表示为开启}else if((shift+1)%2==0)//OFF{FAN_CONTROL_Pin_OFF;FAN_STATE_Flag=0;//风扇状态为0表示为关闭}
}
void Fan_Control_Temp(uint8_t shift1,uint8_t shift2)
{u8 i;char temp1[1];char temp[10]={0x00,0x00,0x0C,0x12,0x12,0x0C,0x00,0x00};//“°”char data1,data2,data3;//十位,个位,分位FAN_TEMP_Control_Flag=0;//风扇温度控制标志位置0,防止设置过程中风扇开启OLED_ShowString(20, 0, "FAN Control");OLED_ShowString(56, 4, ".");//"°"OLED_Set_Pos(75,4); for(i=0;i<8;i++){OLED_WR_Byte(temp[i],OLED_DATA);}OLED_ShowString(83,4,"C");OLED_ShowString(52,6,"SET");data1=FAN_TEMP_Enter[0];OLED_ShowString(40, 4, &data1);data2=FAN_TEMP_Enter[1];OLED_ShowString(48, 4, &data2);data3=FAN_TEMP_Enter[2];OLED_ShowString(64, 4, &data3);if(shift1==0) OLED_ShowString(40, 4, "_");else if(shift1==1) OLED_ShowString(48, 4, "_");else if(shift1==2) OLED_ShowString(64, 4, "_");else if(shift1==3) OLED_ShowString(36, 6, "->");if(shift2!=0){if(shift2==10){temp1[0]=0+0x30;if(shift1==0) OLED_ShowString(40, 4, "0");else if(shift1==1) OLED_ShowString(48, 4, "0");else if(shift1==2) OLED_ShowString(64, 4, "0");}else{temp1[0]=shift2+0x30;if(shift1==0) OLED_ShowString(40, 4, temp1);else if(shift1==1) OLED_ShowString(48, 4, temp1);else if(shift1==2) OLED_ShowString(64, 4, temp1);}if(Enter_Over_Flag==1)//如果确认输入{FAN_TEMP_Enter[shift1]=temp1[0];//存储数据Enter_Over_Flag=0;//清空标志位}}
}
void Fan_Control_Temp_Set(void)
{u8 i,j=0;for(i=0;i<3;i++){if(FAN_TEMP_Enter[i]!=0x2A){j++;}}if(j==3)//所有数据均已设置好{FAN_TEMP_Control_Flag=1;//风扇温度控制标志位置1OLED_ShowString(20, 2, "SET Succeed");}else{OLED_ShowString(28, 2, "DATA Error");}
}
#ifndef __OLED_H
#define __OLED_H#include "stdlib.h"
#include "DELAY.h"
#include <string.h>
#include <stdio.h>
#include "delay.h"/*** OLED模式设置* 0:4线串行模式* 1:并行8080模式*/
#define OLED_MODE 0
#define SIZE 16
#define XLevelL 0x00
#define XLevelH 0x10
#define Max_Column 128
#define Max_Row 64
#define Brightness 0xFF
#define X_WIDTH 128
#define Y_WIDTH 64 #define OLED_CMD 0 //写命令
#define OLED_DATA 1 //写数据/* 端口引脚宏定义,方便程序移植 */
#define GPIO_OLED_CLK RCC_APB2Periph_GPIOC
#define GPIO_OLED_SCLK_Pin GPIO_Pin_7 /* D0 */
#define GPIO_OLED_PIN_Pin GPIO_Pin_8 /* D1 */
#define GPIO_OLED_RES_Pin GPIO_Pin_9 /* RES */
#define GPIO_OLED_DC_Pin GPIO_Pin_10 /* DC *//* 引脚电平设置 */
/** * 注意:需要配置的有RES、DC、CLK、PIN四个引脚,接线CS可不接,当选模式0的时候要接CS*/
/*
#define OLED_CS_Clr() GPIO_ResetBits(GPIOA,GPIO_Pin_8) //CS 片选 => 置零或悬空 当选模式0的时候要连
#define OLED_CS_Set() GPIO_SetBits(GPIOA,GPIO_Pin_8)
*/#define OLED_RST_Clr() GPIO_ResetBits(GPIOC,GPIO_Pin_9) //RES RES => 接RES引脚
#define OLED_RST_Set() GPIO_SetBits(GPIOC,GPIO_Pin_9)#define OLED_DC_Clr() GPIO_ResetBits(GPIOC,GPIO_Pin_10) //DC DC => 接DC引脚
#define OLED_DC_Set() GPIO_SetBits(GPIOC,GPIO_Pin_10)/* 使用4线串行接口时使用 */
#define OLED_SCLK_Clr() GPIO_ResetBits(GPIOC,GPIO_Pin_7)//CLK D0 => 接D0引脚
#define OLED_SCLK_Set() GPIO_SetBits(GPIOC,GPIO_Pin_7)#define OLED_SDIN_Clr() GPIO_ResetBits(GPIOC,GPIO_Pin_8)//PIN D1 => 接D1引脚
#define OLED_SDIN_Set() GPIO_SetBits(GPIOC,GPIO_Pin_8)/* PC0~7,作为数据线 */
#define DATAOUT(x) GPIO_Write(GPIOC,x); //输出 extern char FAN_TEMP_Enter[5];//风扇温度设置存储
extern u8 FAN_STATE_Flag;//风扇状态标志位
extern u8 FAN_TEMP_Control_Flag;//风扇温度控制标志位/* OLED控制用函数 */
void OLED_Clear(void); /* OLED清屏 */
void OLED_Display_On(void); /* OLED开 */
void OLED_ShowPosture(void); /* 提示信息 */
void OLED_Display_Off(void); /* OLED关 */
void OLED_InitConfig(void); /* OLED初始化 */
void OLED_WR_Byte(uint8_t dat,uint8_t cmd); /* 写字节 */
void OLED_Set_Pos(unsigned char x, unsigned char y); /* 设置坐标 */
void OLED_ShowChar(uint8_t x,uint8_t y,uint8_t chr); /* 显示字符 */
void OLED_ShowChar_Adjust(uint8_t size,uint8_t x,uint8_t y,uint8_t chr); //可自己设置大小的字符显示
void OLED_ShowString(uint8_t x,uint8_t y, char *p); /* 显示字符串 */
void OLED_ShowNum(uint8_t x,uint8_t y,u32 num,uint8_t len,uint8_t size); /* 显示数字 */
void OLED_DrawBMP(unsigned char x0, unsigned char y0,unsigned char x1, unsigned char y1,unsigned char BMP[]);/* 显示图片 */
void Board_MPU_Angle_Show(void);
void Platform_MPU_Angle_Show(void);
void Lipo_Voltage_Display(void);
void DHT11_TemHum_Display(void);
void USB_ON_Dispaly(void);
void USB_OFF_Dispaly(void);/* OLED显示函数 */
void OLED_StartDesk(void); //开机画面
void OLED_WIFI(uint8_t shift); //无线信息获取界面
void OLED_WIFI_Name(u16 *Snum); //无线名称显示
void OLED_WIFI_Password(u16 *Snum);//无线密码显示
void OLED_WIFI_IP(u16 *Snum); //无线IP显示
void OLED_AskDesk(uint8_t shift); //用户询问函数
void OLED_Cread_WIFI(uint8_t shift);//用户创建无线选择界面
void OLED_Cread_WIFI_NAME(uint8_t shift1,uint8_t shift2);//用户设置无线名称界面
void OLED_Cread_WIFI_Password(uint8_t shift1,uint8_t shift2);//shift1向下,shift2确认后选择数字
void OLED_Send_WIFI_DATA(uint8_t shift);//发送无线命令显示界面
void OLED_Send_DATA(uint8_t shift);//发送命令显示界面
void OLED_DESK(void);//主界面显示
void OLED_time(void);//时钟显示
void OLED_Temp_Hum(void);//显示温湿度
void OLED_MENU(uint8_t shift);//菜单界面显示
void OLED_Time_Set(uint8_t shift1,uint8_t shift2);//时钟设置界面
void OLED_Time_Set_Check(void);//时钟设置确认界面
void IO_Control_Menu(uint8_t shift);//IO口设置列表
void IO_Control(uint8_t shift1,uint8_t shift2);//IO口设置开关选择
void IO_Control_Data_Set(uint8_t shift1,uint8_t shift2);//IO口设置数据设置成功界面
void Fan_Control(uint8_t shift);//风扇设置界面
void Fan_Control_ON_OFF(uint8_t shift);//风扇开关设置界面
void Fan_Control_ON_OFF_Set(uint8_t shift);//风扇开关设置成功画面
void Fan_Control_Temp(uint8_t shift1,uint8_t shift2);//风扇温度设置界面
void Fan_Control_Temp_Set(void);风扇温度设置确认界面
#endif /* __OLED_H */
3、EEPROM驱动代码
#include "24cxx.h"
#include "DELAY.h"//初始化IIC接口
void AT24CXX_Init(void)
{IIC_Init();
}
//在AT24CXX指定地址读出一个数据
//ReadAddr:开始读数的地址
//返回值 :读到的数据
u8 AT24CXX_ReadOneByte(u16 ReadAddr)
{ u8 temp=0; IIC_Start(); if(EE_TYPE>AT24C16){IIC_Send_Byte(0XA0); //发送写命令IIC_Wait_Ack();IIC_Send_Byte(ReadAddr>>8);//发送高地址IIC_Wait_Ack(); }else IIC_Send_Byte(0XA0+((ReadAddr/256)<<1)); //发送器件地址0XA0,写数据 IIC_Wait_Ack(); IIC_Send_Byte(ReadAddr%256); //发送低地址IIC_Wait_Ack(); IIC_Start(); IIC_Send_Byte(0XA1); //进入接收模式 IIC_Wait_Ack(); temp=IIC_Read_Byte(0); IIC_Stop();//产生一个停止条件 return temp;
}
//在AT24CXX指定地址写入一个数据
//WriteAddr :写入数据的目的地址
//DataToWrite:要写入的数据
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite)
{ IIC_Start(); if(EE_TYPE>AT24C16){IIC_Send_Byte(0XA0); //发送写命令IIC_Wait_Ack();IIC_Send_Byte(WriteAddr>>8);//发送高地址}else{IIC_Send_Byte(0XA0+((WriteAddr/256)<<1)); //发送器件地址0XA0,写数据 } IIC_Wait_Ack(); IIC_Send_Byte(WriteAddr%256); //发送低地址IIC_Wait_Ack(); IIC_Send_Byte(DataToWrite); //发送字节 IIC_Wait_Ack(); IIC_Stop();//产生一个停止条件 delay_mms(10);
}
//在AT24CXX里面的指定地址开始写入长度为Len的数据
//该函数用于写入16bit或者32bit的数据.
//WriteAddr :开始写入的地址
//DataToWrite:数据数组首地址
//Len :要写入数据的长度2,4
void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len)
{ u8 t;for(t=0;t<Len;t++){AT24CXX_WriteOneByte(WriteAddr+t,(DataToWrite>>(8*t))&0xff);}
}//在AT24CXX里面的指定地址开始读出长度为Len的数据
//该函数用于读出16bit或者32bit的数据.
//ReadAddr :开始读出的地址
//返回值 :数据
//Len :要读出数据的长度2,4
u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len)
{ u8 t;u32 temp=0;for(t=0;t<Len;t++){temp<<=8;temp+=AT24CXX_ReadOneByte(ReadAddr+Len-t-1); }return temp;
}
//检查AT24CXX是否正常
//这里用了24XX的最后一个地址(255)来存储标志字.
//如果用其他24C系列,这个地址要修改
//返回1:检测失败
//返回0:检测成功
u8 AT24CXX_Check(void)
{u8 temp;temp=AT24CXX_ReadOneByte(255);//避免每次开机都写AT24CXX if(temp==0X55)return 0; else//排除第一次初始化的情况{AT24CXX_WriteOneByte(255,0X55);temp=AT24CXX_ReadOneByte(255); if(temp==0X55)return 0;}return 1;
}//在AT24CXX里面的指定地址开始读出指定个数的数据
//ReadAddr :开始读出的地址 对24c02为0~255
//pBuffer :数据数组首地址
//NumToRead:要读出数据的个数
void AT24CXX_Read(u16 ReadAddr,u16 NumToRead,u8 *pBuffer)
{while(NumToRead){*pBuffer++=AT24CXX_ReadOneByte(ReadAddr++); NumToRead--;}
}
//在AT24CXX里面的指定地址开始写入指定个数的数据
//WriteAddr :开始写入的地址 对24c02为0~255
//pBuffer :数据数组首地址
//NumToWrite:要写入数据的个数
void AT24CXX_Write(u16 WriteAddr,u16 NumToWrite,u8 *pBuffer)
{while(NumToWrite--){AT24CXX_WriteOneByte(WriteAddr,*pBuffer);WriteAddr++;pBuffer++;}
}
#ifndef __24CXX_H
#define __24CXX_H
#include "iic.h" #define AT24C01 127
#define AT24C02 255
#define AT24C04 511
#define AT24C08 1023
#define AT24C16 2047
#define AT24C32 4095
#define AT24C64 8191
#define AT24C128 16383
#define AT24C256 32767 #define EE_TYPE AT24C02u8 AT24CXX_ReadOneByte(u16 ReadAddr); //指定地址读取一个字节
void AT24CXX_WriteOneByte(u16 WriteAddr,u8 DataToWrite); //指定地址写入一个字节
void AT24CXX_WriteLenByte(u16 WriteAddr,u32 DataToWrite,u8 Len);//指定地址开始写入指定长度的数据
u32 AT24CXX_ReadLenByte(u16 ReadAddr,u8 Len); //指定地址开始读取指定长度数据
void AT24CXX_Write(u16 WriteAddr,u16 NumToWrite,u8 *pBuffer); //从指定地址开始写入指定长度的数据
void AT24CXX_Read(u16 ReadAddr,u16 NumToRead,u8 *pBuffer); //从指定地址开始读出指定长度的数据u8 AT24CXX_Check(void); //检查器件
void AT24CXX_Init(void); //初始化IIC
#endif
4、与ESP8266串口通信(包含串口通信驱动)
#include "usart1.h"
#include <stdarg.h>u8 USART1_Rx_Buff[80];//串口数据存储
u8 USART1_Rx_Length[10];//串口数据存储长度,最多存储9组数据,从USART1_Rx_Length[1]开始记录,USART1_Rx_Length[0]=0
u8 USART1_Rx_Num=0; //串口数据存储组数
u8 USART_Count=0;//数据存储计数
u8 ESP8266_Data_Flag=0;//串口数据处理标志位int fputc(int ch, FILE *f)
{while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET); USART_SendData(USART1, (unsigned char)ch); return ch;
}void USART1_Config(void)
{USART_InitTypeDef USART_InitStructure;/* USART1 工作模式配置 */USART_InitStructure.USART_BaudRate = 115200; //波特率设置:115200USART_InitStructure.USART_WordLength = USART_WordLength_8b; //数据位数设置:8位USART_InitStructure.USART_StopBits = USART_StopBits_1; //停止位设置: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); //初始化USART1USART_Cmd(USART1, ENABLE);// USART1使能//配置串口中断NVIC_InitTypeDef NVIC_InitStrue;USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);// 配置中断优先级NVIC_InitStrue.NVIC_IRQChannel=USART1_IRQn;NVIC_InitStrue.NVIC_IRQChannelCmd=ENABLE;NVIC_InitStrue.NVIC_IRQChannelPreemptionPriority=0;//优先级0NVIC_InitStrue.NVIC_IRQChannelSubPriority=0;//子优先级0NVIC_Init(&NVIC_InitStrue);}/*发送一个字节数据*/void UART1SendByte(unsigned char SendData)
{ USART_SendData(USART1,SendData);while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);
} /*接收一个字节数据*/
unsigned char UART1GetByte(unsigned char* GetData)
{ if(USART_GetFlagStatus(USART1, USART_FLAG_RXNE) == RESET){ return 0;//没有收到数据 }*GetData = USART_ReceiveData(USART1); return 1;//收到数据
}void USART1_IRQHandler(void)
{u8 i;//计数,用于减去之前所有的数据数量总和,算出当前组的数据if(USART_GetITStatus(USART1,USART_IT_RXNE))//中断标志{USART1_Rx_Buff[USART_Count] = USART_ReceiveData(USART1); if(USART1_Rx_Buff[USART_Count-1]==0x0D)//倒数第二个结束位{if(USART1_Rx_Buff[USART_Count]==0x0A)//倒数第一个结束位{USART1_Rx_Num++;//数据存储组数+1i=USART1_Rx_Num-1;USART1_Rx_Length[USART1_Rx_Num]=USART_Count;while(i!=0){USART1_Rx_Length[USART1_Rx_Num]=USART1_Rx_Length[USART1_Rx_Num]-USART1_Rx_Length[i];//减去之前所有的长度i--;}//USART1_Rx_Length[USART1_Rx_Num]=USART_Count-USART1_Rx_Length[USART1_Rx_Num-1];//从0开始计算的个数ESP8266_Data_Flag=1;//数据需要处理标志位置1LED3_Toggle();}}USART_Count++; USART_ClearITPendingBit(USART1, USART_IT_RXNE);//清除中断}
}
#ifndef __USART1_H
#define __USART1_H#include "stm32f10x.h"
#include <stdio.h>
#include <user_config.h>#define USART1_Port GPIOA
#define USART1_TX GPIO_Pin_9 //TX
#define USART1_RX GPIO_Pin_10 //RXextern u8 ESP8266_Data_Flag ;//串口数据处理标志位
extern u8 USART1_Rx_Buff[80];//串口数据存储
extern u8 USART1_Rx_Length[10];//串口数据存储长度,最多存储9组数据,从USART1_Rx_Length[1]开始记录,USART1_Rx_Length[0]=0
extern u8 USART1_Rx_Num; //串口数据存储组数
extern u8 USART_Count;//数据存储计数void USART1_Config(void);
void UART1SendByte(unsigned char SendData);
unsigned char UART1GetByte(unsigned char* GetData);
#endif /* __USART1_H */
5、DS1302驱动代码
#include "DS1302.h"
char time[8];//存储时钟信息
u8 rsec,rmin,rhour,rdate,rmonth,rday,ryear;
u8 init_time[7]={0x00,0x22,0x18,0x04,0x10,0x07,0x20}; void CLK_SDA_IN(void)
{GPIO_InitTypeDef GPIO_InitStructure; //定义一个GPIO口初始化结构体//RCC_APB2PeriphClockCmd(DS1302_PORT, ENABLE); //GPIOA端口RCC时钟使能,已在别处使能GPIO_InitStructure.GPIO_Pin = CLK_SDA_PINS;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IPU; //配置成浮空输入模式GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //传输速率配置成50HZGPIO_Init(DS1302_PORT, &GPIO_InitStructure); //调用库函数,使用上面配置的GPIO_InitStructure初始化GPIO
}void CLK_SDA_OUT(void)
{GPIO_InitTypeDef GPIO_InitStructure; //定义一个GPIO口初始化结构体//RCC_APB2PeriphClockCmd(DS1302_PORT, ENABLE); //GPIOA端口RCC时钟使能GPIO_InitStructure.GPIO_Pin = CLK_SDA_PINS;GPIO_InitStructure.GPIO_Mode = GPIO_Mode_Out_PP; //配置成推挽输出模式GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; //传输速率配置成50HZGPIO_Init(DS1302_PORT, &GPIO_InitStructure); //调用库函数,使用上面配置的GPIO_InitStructure初始化GPIO
}void Write_Byte(u8 byte_1)
{u8 i = 0;CLK_SDA_OUT();//SDA配置为输出for (i=0;i<8;i++) {if((byte_1 & 0x01)) {CLK_SDA_SET;}else{CLK_SDA_RESET;}CLK_SCK_SET; //时钟信号CLK_SCK_RESET;byte_1 >>= 1;}
}u8 Read_Byte(void)
{u8 i = 0;u8 val;CLK_SDA_IN();//SDA配置为输入for (i=0;i<8;i++) {val >>= 1;if(GPIO_ReadInputDataBit(DS1302_PORT,CLK_SDA_PINS) == SET){val = val| 0x80; }CLK_SCK_SET;//时钟信号CLK_SCK_RESET; }return val;
}void Write_Data (u8 WData,u8 Addr)
{CLK_CE_SET; //拉高片选 Write_Byte(Addr); //写入地址Write_Byte(WData); //写入数据//写完后CLK_CE_RESET; //拉低CE CLK_SDA_RESET; //拉低SDA
}u8 Read_Data(u8 Addr)
{u8 Data =0;CLK_CE_SET; //拉高片选Write_Byte(Addr); //写入地址Data = Read_Byte(); //读取数据CLK_CE_RESET; CLK_SDA_RESET; return Data;
}u8 SEC_Read(void)
{rsec = Read_Data(AddrSeconds+1);return rsec;
}
u8 MIN_Read(void)
{rmin = Read_Data(AddrMinutes+1);return rmin;
}u8 HOUR_Read(void)
{rhour = Read_Data(AddrHour+1);return rhour;
}u8 DAY_Read(void)
{rdate = Read_Data(AddrDate+1);return rdate;
}u8 MONTH_Read(void)
{rmonth = Read_Data(AddrMonth+1);return rmonth;
}u8 WEEK_Read(void)
{rday = Read_Data(AddrDay+1);return rday;
}u8 YEAR_Read(void)
{ryear = Read_Data(AddrYear+1);return ryear;
}unsigned char BCD(unsigned char bcd){unsigned char res;res = bcd/16 *10 +bcd%16;return res;}void init_DS1302(void)
{u8 dat;u8 i;u8 Addr=0x80;dat = Read_Data(AddrSeconds+1); if((dat & 0x80)) {Write_Data(0x00,0x8e); for(i = 0;i<7;i++){Write_Data(init_time[i],Addr); Addr+=2;}Write_Data(0x80,0x8e); }}
//获取时间数据
void DS1302_DATA_GET(void)
{time[0] = BCD(SEC_Read());time[1] = BCD(MIN_Read());time[2] = BCD(HOUR_Read());time[3] = BCD(DAY_Read());time[4] = BCD(MONTH_Read());time[5] = BCD(WEEK_Read());time[6] = BCD(YEAR_Read());
}
#ifndef __DS1302__H
#define __DS1302__H
#include "DELAY.h"#define AddrSeconds 0x80
#define AddrMinutes 0x82
#define AddrHour 0x84
#define AddrDate 0x86
#define AddrMonth 0x88
#define AddrDay 0x8A
#define AddrYear 0x8C
#define DS1302_PORT (GPIOA)
#define CLK_CE_PORT (GPIOA)
#define CLK_CE_PINS (GPIO_Pin_3)
#define CLK_SDA_PORT (GPIOA)
#define CLK_SDA_PINS (GPIO_Pin_2)
#define CLK_SCK_PORT (GPIOA)
#define CLK_SCK_PINS (GPIO_Pin_1)#define CLK_SCK_RESET GPIO_ResetBits(DS1302_PORT, CLK_SCK_PINS)
#define CLK_SCK_SET GPIO_SetBits(DS1302_PORT, CLK_SCK_PINS)
#define CLK_SDA_RESET GPIO_ResetBits(DS1302_PORT, CLK_SDA_PINS)
#define CLK_SDA_SET GPIO_SetBits(DS1302_PORT, CLK_SDA_PINS)
#define CLK_CE_RESET GPIO_ResetBits(DS1302_PORT, CLK_CE_PINS)
#define CLK_CE_SET GPIO_SetBits(DS1302_PORT, CLK_CE_PINS)extern char time[8];//存储时钟信息void CLK_SDA_IN(void);
void CLK_SDA_OUT(void);
void init_DS1302(void);
void Write_Byte(u8 Wdata);
u8 Read_Byte(void);
void Write_Data (u8 WData,u8 Addr);
u8 Read_Data(u8 Addr);
void Set_Time(u8 Year, u8 Month, u8 Date, u8 Hour, u8 Minutes, u8 Seconds, u8 Day);
u8 SEC_Read(void);
u8 MIN_Read(void);
u8 HOUR_Read(void);
u8 DAY_Read(void);
u8 MONTH_Read(void);
u8 WEEK_Read(void);
u8 YEAR_Read(void);
unsigned char BCD(unsigned char bcd);
void DS1302_DATA_GET(void);
#endif
6、读写FLASH
#include "STM_FLASH.h"
#include "stm32f10x_flash.h"
//#include "Delay.h"//解锁Flash
void STMFLASH_Unlock(void)
{FLASH->KEYR=FLASH_KEY1;FLASH->KEYR=FLASH_KEY2;
}//flash上锁
void STMFLASH_Lock(void)
{FLASH->CR|=1<<7;//上锁
}//得到Flash的状态
u8 STMFLASH_GetStatus(void)
{ u32 res; res=FLASH->SR;if(res&(1<<0))return 1; //忙else if(res&(1<<2))return 2; //编程错误else if(res&(1<<4))return 3; //写保护return 0; //操作完成
}
//等待操作完成
//time:延时时间
//返回值:状态
u8 STMFLASH_WaitDone(u16 time)
{u8 res;do{res=STMFLASH_GetStatus();if(res!=1)break;//非忙,无需等待,直接退出delay_us(1); time--; }while(time);if(time==0)res=0xff;//TIMEOUTreturn res;
}
//擦除页
//paddr:页地址
//返回值:执行情况
u8 STMFLASH_ErasePage(u32 paddr)
{u8 res=0;res=STMFLASH_WaitDone(0X5FFF);//等待上次操作结束,>20msif(res==0){FLASH->CR|=1<<1;//页擦除FLASH->AR=paddr;//设置页地址FLASH->CR|=1<<6;//开始擦除res=STMFLASH_WaitDone(0X5FFF);//等待操作结束,>20msif(res!=1)//非忙{FLASH->CR&=~(1<<1);//清除页擦除标志}}return res;
}
//在FLASH指定地址写入半字
//faddr:指定地址(此地址必须为2的倍数)
//dat:要写入的数据
//返回值:写入的情况
u8 STMFLASH_WriteHalfWord(u32 faddr, u16 dat)
{u8 res;res=STMFLASH_WaitDone(0XFF);if(res==0)//OK{FLASH->CR|=1<<0;//编程使能*(vu16*)faddr=dat;//写入数据res=STMFLASH_WaitDone(0XFF);//等待操作完成if(res!=1)//操作成功{FLASH->CR&=~(1<<0);//清除PG位}}return res;
}
//读取指定地址的半字(16位数据)
//faddr:读地址
//返回值:对应数据
u16 STMFLASH_ReadHalfWord(u32 faddr)
{return *(vu16*)faddr;
}#if STM32_FLASH_WREN //如果使能了写
//不检查写入
//WriteAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)个数
void STMFLASH_Write_NoCheck(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
{u16 i;for(i=0;i<NumToWrite;i++){STMFLASH_WriteHalfWord(WriteAddr,pBuffer[i]);WriteAddr+=2;//地址增加2}
}//从指定地址开始写入指定长度的数据
//WriteAddr:起始地址(此地址必须为2的倍数)
//pBuffer:数据指针
//NumToWrite:半字(16位)个数#if STM32_FLASH_SIZE<256
#define STM_SECTOR_SIZE 1024 //字节
#else
#define STM_SECTOR_SIZE 2048
#endif
u16 STMFLASH_BUF[STM_SECTOR_SIZE/2];//最多是2K字节void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite)
{u32 secpos; //扇区地址u16 secoff; //扇区内偏移地址(16位计算)u16 secremain; //扇区内剩余地址(16位字计算)u16 i;u32 offaddr; //去掉0x08000000后的地址if(WriteAddr<STM32_FLASH_BASE||(WriteAddr>=(STM32_FLASH_BASE+1024*STM32_FLASH_SIZE)))return;//非法地址STMFLASH_Unlock(); //解锁offaddr=WriteAddr-STM32_FLASH_BASE; //实际偏移地址secpos=offaddr/STM_SECTOR_SIZE; //扇区地址 0~127 for STM32F103RBT6secoff=(offaddr%STM_SECTOR_SIZE)/2; //在扇区内偏移(2个字节为基本单位)secremain=STM_SECTOR_SIZE/2-secoff; //扇区剩余空间大小if(NumToWrite<=secremain)secremain=NumToWrite;//不大于该扇区范围while(1){STMFLASH_Read(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);//读出整个扇区的内容for(i=0;i<secremain;i++)//校验数据{if(STMFLASH_BUF[secoff+i]!=0XFFFF)break;//需要擦除}if(i<secremain)//需要擦除{STMFLASH_ErasePage(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE);//擦除整个扇区for(i=0;i<secremain;i++) STMFLASH_BUF[i+secoff]=pBuffer[i];//STMFLASH_Write_NoCheck(secpos*STM_SECTOR_SIZE+STM32_FLASH_BASE,STMFLASH_BUF,STM_SECTOR_SIZE/2);
//写入整个扇区}else STMFLASH_Write_NoCheck(WriteAddr,pBuffer,secremain);
//写已经擦除了的,直接写入扇区剩余区间if(NumToWrite==secremain)break;//写入结束了else//写入未结束{secpos++; //扇区地址增1secoff=0; //偏移位置为0pBuffer+=secremain; //指针偏移WriteAddr+=secremain; //写地址偏移NumToWrite-=secremain; //字节(16位)个数递减if(NumToWrite>(STM_SECTOR_SIZE/2))secremain=STM_SECTOR_SIZE/2;//下一个扇区还是写不完else secremain=NumToWrite;//下一个扇区可以写完}};STMFLASH_Lock();//上锁
}
#endif//从指定地址开始读出指定长度的数据
//ReadAddr:起始地址
//pBuffer:数据指针
//NumToWrite:半字(16位)个数
void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead)
{u16 i;for(i=0;i<NumToRead;i++){pBuffer[i]=STMFLASH_ReadHalfWord(ReadAddr);//读取2个字节ReadAddr+=2;//偏移2个字节}
}
#ifndef __STM_FLASH_H__
#define __STM_FLASH_H__
#include "user_Config.h"//用户根据自己的需求设置容量
#define STM32_FLASH_SIZE 512 //所选STM32的FLASH容量大小
#define STM32_FLASH_WREN 1 //使能FLASH写入(0,不使能;1,使能)//FLASH起始地址
#define STM32_FLASH_BASE 0x08000000 //STM32 FLASH起始地址//FLASH解锁键值
#define FLASH_KEY1 0X45670123
#define FLASH_KEY2 0XCDEF89AB//要写入STM32 FLASH的数组
//#define SIZE sizeof(FLASH_Buffer) //数组长度
//#define FLASH_SAVE_ADDR 0X08070000 //设置FLASH 保护地址(必须为偶数,且其值要大于本代码所占用FLASH的大小+0x8000000)
#define FLASH_SAVE_ADDR 0X0803FF5C //设置FLASH 保护地址(必须为偶数,且其值要大于本代码所占用FLASH的大小+0x8000000)void STMFLASH_Unlock(void); //FLASH解锁
void STMFLASH_Lock(void); //FLASH上锁
u8 STMFLASH_GetStatus(void); //获得状态
u8 STMFLASH_WaitDone(u16 time); //等待操作结束
u8 STMFLASH_ErasePage(u32 paddr); //擦除页
u8 STMFLASH_WriteHalfWord(u32 faddr, u16 dat); //写入半字
u16 STMFLASH_ReadHalfWord(u32 faddr); //读出半字
void STMFLASH_WriteLenByte(u32 WriteAddr,u32 DataToWrite,u16 Len); //指定地址开始写入指定长度的数据
u32 STMFLASH_ReadLenByte(u32 ReadAddr,u16 Len); //指定地址开始读取指定长度的数据
void STMFLASH_Write(u32 WriteAddr,u16 *pBuffer,u16 NumToWrite); //从指定地址开始写入指定长度的数据
void STMFLASH_Read(u32 ReadAddr,u16 *pBuffer,u16 NumToRead); //从指定地址开始读出指定长度的数据
#endif
以上为本开发板一些比较重要的代码,主要是提供一些外设的驱动代码汇总和OLED显示的一些思路。驱动代码都是经过测试的,有需求的可对附加功能进行删减之后直接使用,整个系统完整代码只用于本人私下测试使用,暂不放出。
五、优化方向
这个电路板成本价在50元左右,若批量大了成本还会大幅度下降,相比某宝功能差不多的物联网开发板上百元的价格还是有性价比的,但是缺乏了相关资源如教程的配套服务。要完善的功能有以下几点:
- ESP8266程序下载电路,此前该电路在设计上存在很大问题
- 丰富ESP8266的功能,目前仅与STM32进行串口通信
- 丰富ESP8266与STM32相结合的应用,能发挥ESP8266作为通信节点,STM32作为主控芯片进行数据运算等特点的应用,将会是该开发板的经典应用
不足之处还望各位大佬不吝赐教!
物联网系列②——使用ESP8266与STM32进行物联网开发板设计相关推荐
- 物联网系列⑤——基于ESP8266与点灯科技平台的氛围灯设计(接入小爱同学)
物联网系列⑤--基于ESP8266与点灯科技平台的氛围灯设计(接入小爱同学) 一.设计目标 二.电路设计 三.思路介绍 四.ESP8266代码 一.设计目标 使用点灯科技平台接入物联网,可通过手机点灯 ...
- 官方STM32的NUCLEO开发板使用
官方STM32的NUCLEO开发板使用 概述:因工作需求,先买了stm32的NUCLEO开发板做测试板,本人使用的是L073RZ这块板子,也是第一次接触stm32,摸索状态.这里记录一下使用过程,做笔 ...
- 【STM32 .Net MF开发板学习-02】GPIO测试
前段时间我借用市面上现成的Corex-M3开发板,打造了最低价的.Net Micro Framework开发板(参见<免费发放firmwave,打造史上最低价.Net MF开发板>),在此 ...
- STM32 BLDC电机驱动开发板资料 反电动势B-EMF过零检测
STM32 BLDC电机驱动开发板资料 反电动势B-EMF过零检测 华愉电子工作室
- STM32MP1系列教程连载-华清远见FS-MP1A开发板使用
STM32MP1系列教程连载-华清远见FS-MP1A开发板使用 1.1 FS_MP1A硬件资源介绍 FS-MP1A采用STM32MP157A处理器.STM32MP157A是基于Cortex-A7 32 ...
- USB开发—STM32 USB Audio 开发板介绍(Feedback)
USB开发-STM32 USB Audio 开发板介绍(Feedback) 一.背景 我个人从事音频行业有好几年的时间.后面慢慢的做起了声卡,也就是USB Audio.自己也走了不少的弯路.之前一起是 ...
- 手把手教你用Arduino接入阿里云物联网平台,ESP8266连接阿里云物联网平台必看教程...
使用Ardui no 的方式快速连接阿里云物联网平台. 文中提到的 AliyunIoTSDK 这个 Arduino 库,可以在 Arduino 库商店里搜索到(搜索 AliyunIoTSDK) Ali ...
- 【临时抱佛脚之蓝桥杯物联网日志】蓝桥杯基本情况,开发板
一.蓝桥杯基本情况 二.了解开发板 1.LoRa 终端 2.传感器模块 温度传感器 矩阵键盘 模拟电压输出 脉冲输出 光敏与红外热释电 3.调试器 4.时钟 5.OLED显示屏 6.继电器 7.通用接 ...
- 物联网开发板设计笔记 (1/7)__ 设计思路
最近给咱们的用户做了 2 个开发板,以后大家学习物联网开发就方便点了,这里把设计的过程分享给大家.在设计之初主要有以下几个方面的考虑: 1.目前直连平台的物联网硬件终端产品主要采用移动通信和 wifi ...
- 【STM32 .Net MF开发板学习-11】步进电机控制(非PWM模式)
选用的步进电机的型号为28BYJ-48(或MP28GA,5V,转速比1/64),驱动电路选用 uln2003芯片的驱动板,其控制时序图如下: 四相八拍:A->AB->B ->BC - ...
最新文章
- 原理 快速邻近匹配_论文推荐 | 陈晓勇:低空摄影测量立体影像匹配的现状与展望...
- 在15分钟内使用Spring Boot和Spring Security构建一个Web应用程序
- 使用rx-java的异步抽象
- mysql json 引号 双引号_关于JSON字符串key缺少双引号的解决方法 的讲解
- 开机自启动redis
- D2Admin - 基于vue的清新后台模板
- libsvm——参数优化工具grid.py的使用
- 关于发布WP 8.1应用信息不匹配问题的解决办法
- 【R语言教程】不一样的零基础教程,数据分析到论文写作一站式完成
- cloudera-scm-service报错server已死,但pid文件仍存问题解决
- 安装NVIDIA显卡驱动
- 数字逻辑:多级门电路
- 思岚科技A1,A2雷达驱动安装
- 抖音小店保证金被扣除怎么办?抖音小店货款什么时候结算?
- 如何利用PDF编辑软件将pdf文字修改
- python实现12306火车票查询
- 优秀的NAS不光只有群晖,看看威联通在安全性上如何K掉群晖
- 语音信号处理-概念(一):时域信号(横轴:时间;纵轴:幅值)、频谱图(横轴:频率;纵轴:幅值)--傅里叶变换-->时频谱图(语谱图/声谱图)【横轴:时间;纵轴:频率;颜色深浅:幅值】
- 通过分辨率区分iPhone型号(更新至13系列)
- 分布式消息队列RocketMQ与Kafka的18项差异之“拨乱反正“之2
热门文章
- 湖南超级计算机研学,以超算之速,跨越弦歌千年 | 建宁实验中学中考励志研学...
- j2ee java是什么意思,j2ee是什么
- confluence 制作流程图_怎么利用软件绘制结构示意图 软件流程图绘制
- 计算机源代码英语,计算机源代码编写规范(国外英文资料).doc
- JavaScript浏览器对象之window对象详解
- linux下python网络编程框架-twisted安装手记,linux编程_Linux下Python网络编程框架安装日志...
- jQuery学习笔记之选取选定复选框的同行某列元素
- 分享常见的视频加密算法原理及其优缺点
- 保存网页图片的八种方法
- web前端开发面试题(五)