MCU起航 lazybeach
关注数: 521 粉丝数: 1,237 发帖数: 6,113 关注贴吧数: 49
ESP8266_09基于IIC控制的OLED屏幕 这是我2019年写的学习笔记,首发我的博客:MCU起航,现在转载到贴吧,大家感兴趣的看看就行。 从第一节到第九节(也就是这一节),说的都是ESP8266的基本应用,例如GPIO、定时器、中断、PWM等等。从后面开始,将陆续说一下基于网络的用法,毕竟这是个联网的芯片,还是要联网玩,才更能体现它的特点。但偶尔,我可能还会说一下它的硬件的基本用法,例如ADC、SPI等,看情况吧,时间富裕与否~ 好,这一节,主要说一下ESP8266上面的IIC接口。是的,它有SPI接口,也有IIC接口。但IIC接口是使用GPIO模拟的,也就是说,你可以使用8266上的任意两个GPIO模拟出IIC接口来。同时,每个管脚内部都有上拉电阻,无需外接。 注:ESP8266只能用做IIC主设备,不能用做从设备。 那我们是否还要写一堆IIC的start函数、stop函数? 不用,官方的SDK已经给我们写好了整个的IIC库,只要配置好要用的管脚,直接调用函数即可,例如: i2c_master_start(void); i2c_master_stop(void); i2c_master_writeByte(uint8 wrdata); 如何使用?很简单,分四步: 1、添加相关源文件和头文件 把i2c_master.c拷入app下的driver文件夹,把i2c_master.h拷入app下的include下的driver文件夹。 2、选择要用到的GPIO 打开i2c_master.h文件,管脚选择部分如下所示: #define I2C_MASTER_SDA_MUXPERIPHS_IO_MUX_GPIO2_U #define I2C_MASTER_SCL_MUXPERIPHS_IO_MUX_MTMS_U #define I2C_MASTER_SDA_GPIO 2 #define I2C_MASTER_SCL_GPIO 14 #define I2C_MASTER_SDA_FUNC FUNC_GPIO2 #define I2C_MASTER_SCL_FUNC FUNC_GPIO14 通过这6个宏定义,配置好IIC接口要用的时钟脚和数据脚,我这里想用GPIO12和14,所以改成如下的样子: #define I2C_MASTER_SDA_MUXPERIPHS_IO_MUX_MTDI_U #define I2C_MASTER_SCL_MUXPERIPHS_IO_MUX_MTMS_U #define I2C_MASTER_SDA_GPIO 12 #define I2C_MASTER_SCL_GPIO 14 #define I2C_MASTER_SDA_FUNC FUNC_GPIO12 #define I2C_MASTER_SCL_FUNC FUNC_GPIO14 关于管脚的名字,主要看eagle_soc.h文件。 3、初始化IIC管脚 通过下面的函数实现: i2c_master_gpio_init(); 4、开始写数据 用过24C02的童鞋都知道,IIC的写操作,前后就几步:开始信号、写入设备地址、等待应带、写入存储地址、等待应答、写入数据、结束信号。这里结合SDK中的例程IOT_DEMO中的IIC代码,实现写数据的函数如下: boolICACHE_FLASH_ATTR Write_IIC_Data(unsigned char IIC_Data) { uint8ack; i2c_master_start(); i2c_master_writeByte(0x78); //D/C#=0; R/W#=0 ack= i2c_master_getAck(); if(ack) { os_printf("addrnot ack when tx write cmd \n"); i2c_master_stop(); returnfalse; } i2c_master_writeByte(0x40); //write data ack= i2c_master_getAck(); if(ack) { os_printf("addrnot ack when tx write cmd \n"); i2c_master_stop(); returnfalse; } i2c_master_writeByte(IIC_Data); ack= i2c_master_getAck(); if(ack) { os_printf("addrnot ack when tx write cmd \n"); i2c_master_stop(); returnfalse; } i2c_master_stop(); } 上面代码中出现的函数,例如i2c_master_start()、i2c_master_writeByte(0x78)、i2c_master_getAck();等,都已经在i2c_master.c中写好了。换句话说,我们只需要像堆积木一样,按照特定的顺序把这些函数摆下来就行了。 so,是不是很简单? 如何演示? 这里使用一个0.96寸的,带有IIC接口的OLED屏幕。这类屏幕按照我见过的接口不同,分两种:一种是4针的,只能接IIC接口;一种是7针的,既能接IIC,又能接SPI。我手里这个是7针的,出厂默认SPI接口,怎么切换到IIC,我看了半天手册:看起来不难,当我翻开我的液晶背面的时候,发现是这样:所以我只把SPI字符旁边的电阻改到IIC旁边就可以了。 程序使用卖家提供的代码,做了一下移植。会用IIC的自然就懂了,不懂就说明你还没学好IIC。 7针的接口,针脚功能如下:虽然IIC只用到CLK和SDA两个脚,但是这里还要注意下复位管脚,要给它接一个高电平,否则无法工作。 程序移植完成,保存、清理、编译、下载一条龙,然后重新上电,效果如下所示:程序里使用了一个软件定时器,每隔3秒刷新一下图片。
ESP8266_08基于flash数据掉电保护 这是我2019年写的学习笔记,首发我的博客:MCU起航,现在转载到贴吧,大家感兴趣的看看就行。 这一节主要研究一下flash的用法,目的嘛,实现数据的掉电保护。 听起来像EEPROM? 确实很像,但不是!以STM32为例,片上是没有EEPROM的。但是,可以把一部分ROM当做EEPROM,通过程序进行擦写,最终实现的效果和EEPROM几乎是一样的。 那,怎么选这段ROM?一般是选flash的最后一个页(它是以页为单位的)。因为烧程序的时候,程序是从前往后开始烧录的,只要你的程序没有大到占用了最后一个页,那就能用。 ESP8266在这方面其实跟32很像,区别主要有两点: 1、ESP8266是以扇区为单位,一个扇区4KB。 2、ESP8266的最后4个扇区不能动,所以咱们要用的话,可以选倒数第5个扇区。 看下面的图(下图及相关说明转自乐鑫的相关手册):上面两个图分别是不支持在线升级和支持在线升级的固件,在flash中的布局情况。 系统程序:用于存放系统运行必要的固件。 用户数据:当系统数据未占满整个Flash空间时,空闲区域均可用于存放用户数据。 用户参数:地址由用户自定义,IO T _Demo 中设置为0X3C000开始的4个扇区,用户可以设置为任意未占用的地址。 系统参数:固定为 Hash 的最后4个扇区。 BOOT信息:位于 FOTA 固件的分区1,存放FOTA升级预留信息。 预留:位于 FOTA 固件的分区2,与分区1 BOOT信息区对应的预留区域。 注:FLASH中每扇区为4KB。 注:上述信息参考手册2a-esp8266-sdk_getting_started_guide_cn。 根据上面给出的截图和信息,可以知道,如果要实现类似EEPROM的效果,需要把数据存到“用户数据”这一部分。用户数据在flash中有两部分,只要是没有被占用的,都可以。为了简单计算,这里建议大家使用倒数第五个扇区。 如果后期你对flash的布局了解的足够多了,可以使用任意可用的扇区,但是在初期,建议你还是先这么用。 接下来说用法,结合串口做演示(终于不用LED了)。最终实现的效果,上电的时候先把一组数据写入flash,然后循环读取这部分数据,并通过串口打印出来。开始之前先包含以下头文件: #include "spi_flash.h" 相关的读写函数都在里面了。 步骤简单的令人发指,读写都算进去,只需要4步: 1、选择你要写入的扇区 因为每个人手里的模块flash大小都有可能不一样,所以要先根据你的flash大小,计算一下你的倒数第五个扇区的编号是多少。 以我的为例,我的模块是16MBit的,也就是2MB,换算成KB是2048KB,再换算成扇区的个数是2048/4,得到512. 512个扇区,它们的编号从0开始,也就是0~511,那么倒数第五个的编号就是507. 所以我这里的代码写成这样: #define MY_ESP8266_FLASH 2048 #define USER_DATA_SEC (MY_ESP8266_FLASH/ 4 - 1 - 4) uint32 hello[5]= {1,2,3,4,5}; uint32 read[5]; 你们只需要把MY_ESP8266_FLASH后面的数值改成你的就行了。后面的两个数组一个用来存放被写入的数据,另一个用来存放读出的数据。 为什么是uint32类型?后面说! 2、擦除该扇区 无论你要写哪个扇区,一律先擦后写! spi_flash_erase_sector(USER_DATA_SEC); 好简单,不解释~ 3、写入数据 spi_flash_write(USER_DATA_SEC* 4 * 1024, hello, 5 * 4); 该函数共有三个参数: 第一个参数:写入flash的目的地址。虽然前面换算了半天的扇区,这里还是要换算回去。 第二个参数:被写入数据的指针。 第三个参数:数据长度,也就是被写入数据的大小。因为uint32占用4个字节,所以用数组元素个数乘以4. 回到刚才的问题,为什么一定要uint32类型? 答:规定!flash读写必须4字节对齐,所以定义的时候尽量是uint32类型。 4、读出数据 spi_flash_read(USER_DATA_SEC* 4 * 1024, read, 5 * 4); 读取的地址、存放的位置、读取的长度,好简单~~~ 注:参考手册2c-esp8266_non_os_sdk_api_reference_cn的45页,和99a-esp8266_flash_rw_operation_cn_v1.0。 程序里使用了一个软件定时器,每隔3秒通过串口打印输出一下读取到的数据,波特率115200. 保存、清理、编译、下载一条龙,然后重新上电,效果如下所示:到此,flash的用法说完了。
首页 1 2 下一页