物联网系列②——使用ESP8266与STM32进行物联网开发板设计

  • 一、设计目标
  • 二、电路设计
    • 1、原理图设计
    • 2、电路板展示
  • 三、目前实现的功能
  • 四、代码编写
    • 1、DHT11驱动代码
    • 2、0.96寸OLED显示代码(包含驱动)
    • 3、EEPROM驱动代码
    • 4、与ESP8266串口通信(包含串口通信驱动)
    • 5、DS1302驱动代码
    • 6、读写FLASH
  • 五、优化方向

一、设计目标

在ESP8266网络服务器的学习过程中,产生了制作一个ESP8266与STM32物联网开发板的想法。
      该开发板具备以下功能:

  1. 主控芯片:STM32F103RCT6 ,具备CAN,I2C等丰富的外设,同时拥有256KB FLASH,便于代码的扩展。用作该电路的主控芯片,进行数据处理,实现对各种外设的控制。
  2. 物联网芯片:ESP12-F,作为云端与STM32通信的节点,负责数据传输。
  3. LED指示灯:4*LED指示灯,进行系统不同工作状态指示,如电源指示,系统开启指示,通讯指示等等。
  4. 0.96寸OLED:使用4线SPI通信,与按键结合进行系统功能设置.通过2.54MM母排与STM32F103RCT6连接。
  5. 3按键:3个按键接入STM32,功能分别为:返回键,向下键,OK键。3按键外接一个LED,模拟自带LED的按键模块效果。
  6. 温湿度模块:DHT11,进行温湿度采集,数据于OLED和云端显示
  7. 实时时钟:DS1302,用于离线状态的实时时钟显示,于OLED中显示。使用CR1220为其供电。
  8. EEPROM:记录系统运行数据,WIFI账号密码等,考虑记录温湿度数据,形成大数据
  9. 串口芯片:CH340,与电脑进行串口通信,同时也是STM32与ESP8266的程序下载端口,通过跳线帽选择下载程序的目标,分别对其进行程序下载
  10. CAN通信:使用TJA1050T和RJ45网口进行CAN通信
  11. 供电:通过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、电路板展示



三、目前实现的功能

因平时时间有限,仅实现以下功能:

  1. OLED驱动:
          主界面:显示年月日时分秒等时间信息,显示当前温湿度
          菜单界面:通过向下键移动光标,通过OK键对无线账号名称密码设置,时间设置,IO口电平控制,风扇控制等进行选择。
          无线设置界面
          时间设置界面
          IO口控制界面
          风扇控制界面
          界面切换算法

  2. DS1302驱动:时间的获取和设置

  3. DHT11驱动:温湿度数据获取

  4. 无线账号密码设置和时间设置算法,通过按键操作和OLED显示屏显示完成此功能,此部分内容更多的是算法层面的代码编写

  5. IO口电平控制:与4点算法类似,通过按键设置IO口的电平状态,并反馈于OLED界面

  6. 风扇控制:通过外接继电器,通过一个IO口控制继电器的开关,继电器接风扇,从而实现IO口对风扇开关的控制。结合了DHT11温湿度传感器,可设置温度高于多少度时风扇自动开启,如温度高于25°C时风扇自动开启,低于25°C时风扇便关闭了,类似智能家居的联动功能

  7. EEPROM驱动:实现对EEPROM数据的写入和读取

  8. CAN通信:实现两设备间数据的发送和获取

  9. 串口通信:实现与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元左右,若批量大了成本还会大幅度下降,相比某宝功能差不多的物联网开发板上百元的价格还是有性价比的,但是缺乏了相关资源如教程的配套服务。要完善的功能有以下几点:

  1. ESP8266程序下载电路,此前该电路在设计上存在很大问题
  2. 丰富ESP8266的功能,目前仅与STM32进行串口通信
  3. 丰富ESP8266与STM32相结合的应用,能发挥ESP8266作为通信节点,STM32作为主控芯片进行数据运算等特点的应用,将会是该开发板的经典应用

不足之处还望各位大佬不吝赐教!

物联网系列②——使用ESP8266与STM32进行物联网开发板设计相关推荐

  1. 物联网系列⑤——基于ESP8266与点灯科技平台的氛围灯设计(接入小爱同学)

    物联网系列⑤--基于ESP8266与点灯科技平台的氛围灯设计(接入小爱同学) 一.设计目标 二.电路设计 三.思路介绍 四.ESP8266代码 一.设计目标 使用点灯科技平台接入物联网,可通过手机点灯 ...

  2. 官方STM32的NUCLEO开发板使用

    官方STM32的NUCLEO开发板使用 概述:因工作需求,先买了stm32的NUCLEO开发板做测试板,本人使用的是L073RZ这块板子,也是第一次接触stm32,摸索状态.这里记录一下使用过程,做笔 ...

  3. 【STM32 .Net MF开发板学习-02】GPIO测试

    前段时间我借用市面上现成的Corex-M3开发板,打造了最低价的.Net Micro Framework开发板(参见<免费发放firmwave,打造史上最低价.Net MF开发板>),在此 ...

  4. STM32 BLDC电机驱动开发板资料 反电动势B-EMF过零检测

    STM32 BLDC电机驱动开发板资料 反电动势B-EMF过零检测 华愉电子工作室

  5. STM32MP1系列教程连载-华清远见FS-MP1A开发板使用

    STM32MP1系列教程连载-华清远见FS-MP1A开发板使用 1.1 FS_MP1A硬件资源介绍 FS-MP1A采用STM32MP157A处理器.STM32MP157A是基于Cortex-A7 32 ...

  6. USB开发—STM32 USB Audio 开发板介绍(Feedback)

    USB开发-STM32 USB Audio 开发板介绍(Feedback) 一.背景 我个人从事音频行业有好几年的时间.后面慢慢的做起了声卡,也就是USB Audio.自己也走了不少的弯路.之前一起是 ...

  7. 手把手教你用Arduino接入阿里云物联网平台,ESP8266连接阿里云物联网平台必看教程...

    使用Ardui no 的方式快速连接阿里云物联网平台. 文中提到的 AliyunIoTSDK 这个 Arduino 库,可以在 Arduino 库商店里搜索到(搜索 AliyunIoTSDK) Ali ...

  8. 【临时抱佛脚之蓝桥杯物联网日志】蓝桥杯基本情况,开发板

    一.蓝桥杯基本情况 二.了解开发板 1.LoRa 终端 2.传感器模块 温度传感器 矩阵键盘 模拟电压输出 脉冲输出 光敏与红外热释电 3.调试器 4.时钟 5.OLED显示屏 6.继电器 7.通用接 ...

  9. 物联网开发板设计笔记 (1/7)__ 设计思路

    最近给咱们的用户做了 2 个开发板,以后大家学习物联网开发就方便点了,这里把设计的过程分享给大家.在设计之初主要有以下几个方面的考虑: 1.目前直连平台的物联网硬件终端产品主要采用移动通信和 wifi ...

  10. 【STM32 .Net MF开发板学习-11】步进电机控制(非PWM模式)

    选用的步进电机的型号为28BYJ-48(或MP28GA,5V,转速比1/64),驱动电路选用 uln2003芯片的驱动板,其控制时序图如下: 四相八拍:A->AB->B ->BC - ...

最新文章

  1. 原理 快速邻近匹配_论文推荐 | 陈晓勇:低空摄影测量立体影像匹配的现状与展望...
  2. 在15分钟内使用Spring Boot和Spring Security构建一个Web应用程序
  3. 使用rx-java的异步抽象
  4. mysql json 引号 双引号_关于JSON字符串key缺少双引号的解决方法 的讲解
  5. 开机自启动redis
  6. D2Admin - 基于vue的清新后台模板
  7. libsvm——参数优化工具grid.py的使用
  8. 关于发布WP 8.1应用信息不匹配问题的解决办法
  9. 【R语言教程】不一样的零基础教程,数据分析到论文写作一站式完成
  10. cloudera-scm-service报错server已死,但pid文件仍存问题解决
  11. 安装NVIDIA显卡驱动
  12. 数字逻辑:多级门电路
  13. 思岚科技A1,A2雷达驱动安装
  14. 抖音小店保证金被扣除怎么办?抖音小店货款什么时候结算?
  15. 如何利用PDF编辑软件将pdf文字修改
  16. python实现12306火车票查询
  17. 优秀的NAS不光只有群晖,看看威联通在安全性上如何K掉群晖
  18. 语音信号处理-概念(一):时域信号(横轴:时间;纵轴:幅值)、频谱图(横轴:频率;纵轴:幅值)--傅里叶变换-->时频谱图(语谱图/声谱图)【横轴:时间;纵轴:频率;颜色深浅:幅值】
  19. 通过分辨率区分iPhone型号(更新至13系列)
  20. 分布式消息队列RocketMQ与Kafka的18项差异之“拨乱反正“之2

热门文章

  1. 湖南超级计算机研学,以超算之速,跨越弦歌千年 | 建宁实验中学中考励志研学...
  2. j2ee java是什么意思,j2ee是什么
  3. confluence 制作流程图_怎么利用软件绘制结构示意图 软件流程图绘制
  4. 计算机源代码英语,计算机源代码编写规范(国外英文资料).doc
  5. JavaScript浏览器对象之window对象详解
  6. linux下python网络编程框架-twisted安装手记,linux编程_Linux下Python网络编程框架安装日志...
  7. jQuery学习笔记之选取选定复选框的同行某列元素
  8. 分享常见的视频加密算法原理及其优缺点
  9. 保存网页图片的八种方法
  10. web前端开发面试题(五)