赞
踩
在ESP8266网络服务器的学习过程中,产生了制作一个ESP8266与STM32物联网开发板的想法。
该开发板具备以下功能:
(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部分):
因平时时间有限,仅实现以下功能:
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功能
#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表示为1 if(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
#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 ON OLED_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 OFF OLED_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 panel OLED_WR_Byte(0x00,OLED_CMD);//---set low column address OLED_WR_Byte(0x10,OLED_CMD);//---set high column address OLED_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 register OLED_WR_Byte(0xCF,OLED_CMD);// Set SEG Output Current Brightness OLED_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 display OLED_WR_Byte(0xA8,OLED_CMD);//--set multiplex ratio(1 to 64) OLED_WR_Byte(0x3f,OLED_CMD);//--1/64 duty OLED_WR_Byte(0xD3,OLED_CMD);//-set display offset Shift Mapping RAM Counter (0x00~0x3F) OLED_WR_Byte(0x00,OLED_CMD);//-not offset OLED_WR_Byte(0xd5,OLED_CMD);//--set display clock divide ratio/oscillator frequency OLED_WR_Byte(0x80,OLED_CMD);//--set divide ratio, Set Clock as 100 Frames/Sec OLED_WR_Byte(0xD9,OLED_CMD);//--set pre-charge period OLED_WR_Byte(0xF1,OLED_CMD);//Set Pre-Charge as 15 Clocks & Discharge as 1 Clock OLED_WR_Byte(0xDA,OLED_CMD);//--set com pins hardware configuration OLED_WR_Byte(0x12,OLED_CMD); OLED_WR_Byte(0xDB,OLED_CMD);//--set vcomh OLED_WR_Byte(0x40,OLED_CMD);//Set VCOM Deselect Level OLED_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/disable OLED_WR_Byte(0x14,OLED_CMD);//--set(0x10) disable OLED_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 panel OLED_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);//hour data1=time_set[2];data2=time_set[3];OLED_ShowString(56, 2,&data1);OLED_ShowString(64, 2,&data2);//min data1=time_set[0];data2=time_set[1];OLED_ShowString(80, 2,&data1);OLED_ShowString(88, 2,&data2);//sec OLED_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);//year OLED_ShowString(56, 4,"."); data1=time_set[8];data2=time_set[9];OLED_ShowString(64, 4,&data1);OLED_ShowString(72, 4,&data2);//mon OLED_ShowString(80, 4,"."); data1=time_set[6];data2=time_set[7];OLED_ShowString(88, 4,&data1);OLED_ShowString(96, 4,&data2);//day data1=time_set[10];OLED_ShowString(116, 4,&data1);//week if(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");//设置PC13 OLED_ShowString(30, 4, "PC12");//设置PC12 OLED_ShowString(30, 6, "PB15");//设置PB15 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, "->"); } 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;//风扇温度控制标志位置1 OLED_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 */
#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 AT24C02 u8 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
#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; //波特率设置:115200 USART_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); //初始化USART1 USART_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;//优先级0 NVIC_InitStrue.NVIC_IRQChannelSubPriority=0;//子优先级0 NVIC_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++;//数据存储组数+1 i=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;//数据需要处理标志位置1 LED3_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 //RX extern 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 */
#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; //传输速率配置成50HZ GPIO_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; //传输速率配置成50HZ GPIO_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
#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;//TIMEOUT return res; } //擦除页 //paddr:页地址 //返回值:执行情况 u8 STMFLASH_ErasePage(u32 paddr) { u8 res=0; res=STMFLASH_WaitDone(0X5FFF);//等待上次操作结束,>20ms if(res==0) { FLASH->CR|=1<<1;//页擦除 FLASH->AR=paddr;//设置页地址 FLASH->CR|=1<<6;//开始擦除 res=STMFLASH_WaitDone(0X5FFF);//等待操作结束,>20ms if(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 STM32F103RBT6 secoff=(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++; //扇区地址增1 secoff=0; //偏移位置为0 pBuffer+=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元左右,若批量大了成本还会大幅度下降,相比某宝功能差不多的物联网开发板上百元的价格还是有性价比的,但是缺乏了相关资源如教程的配套服务。要完善的功能有以下几点:
不足之处还望各位大佬不吝赐教!
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。