前期回顾:
I2C详解学习 - nRF52832蓝牙芯片 TWI-I2C学习详解笔记
0.前言(文末有福利)
nRF52832蓝牙芯片上用4pin的I2C OLED屏幕显示温湿度:
淘宝买的屏幕模块,给的资料如下:
给的参考代码包含Arduino、C51、STM平台,但是对于Nordic蓝牙芯片,并没有。根据之前的文章,我们可知,Nordic蓝牙芯片的I2C驱动官方已经写好,我们只需要调用接口就可以实现I2C功能,如SHT3x温湿度传感器等。
1. 关于OLED显示屏的介绍
通常我们所用的OLED屏有白色、蓝色、黄蓝双色等几种;屏的大小为0.96寸,像素点为128*64,所以我们也称之为0.96OLED屏或者12864屏。
内部驱动IC为SSD1306;通信方式一般为SPI或者I2C。如下图所示,配置哪种模式主要是根据BS0、BS1和BS2这三个管脚的电平逻辑来的。
如手册上关于I2C地址的描述,根据DC引脚电平的不同,地址为,0111100和0111101两种,通常我们设置DC引脚接地,所以作为I2C从机的七位地址为0111100;又因为我们与驱动IC交互时,都是主机发送命令或者数据到IC,也就是只有写数据,没有读数据,所以从机地址为0x78。
通信方式如上图所示:先发送从机地址,再发送命令字节,接着发送数据字节。注意每次主机要等待从机的应答。下图为写命令和写数据的代码示例。
2. 通过分析参考代码了解OLED屏幕
2.1先从STM32平台的参考code入手
连头文件都没给,写的比较烂,不过能跑起来。
2.2 Main函数入手了解OLED工作方式:
Main函数中:IO初始化—OLED初始化—OLED填充—图片轮流显示
int main() { //point= &picture_tab[0]; point = &word_show_1[0]; IO_init();
OLED_init(); OLED_full(); delay_ms(1000); //OLED_clear();
while(1) { Picture_display(point); delay_ms(200);
Picture_ReverseDisplay(point); delay_ms(200);
} } |
(1)IO初始化没什么讲的,主要是配置IO口等。
(2)OLED屏幕初始化函数如下,主要是向屏幕模组写入25个初始化命令。
OLED_init(void)-- OLED_send_cmd(OLED_init_cmd[i])。
(3)发送每个初始化命令执行的步骤:I2C开始—写入0x00—写入命令—I2C结束。
(4)初始化屏幕的命令有25个。每个命令8bit,具体每个命令的作用在代码中有详细的中文介绍。
//oled初始化 void OLED_init(void) { unsigned char i; for(i=0;i<25;i++) { OLED_send_cmd(OLED_init_cmd[i]); } } //向oled 发送命令 void OLED_send_cmd(unsigned char o_command) {
IIC_start(); IIC_write(0x00); IIC_write(o_command); IIC_stop();
} const unsigned char OLED_init_cmd[25]= { /*0xae,0X00,0X10,0x40,0X81,0XCF,0xff,0xa1,0xa4, 0xA6,0xc8,0xa8,0x3F,0xd5,0x80,0xd3,0x00,0XDA,0X12, 0x8d,0x14,0xdb,0x40,0X20,0X02,0xd9,0xf1,0xAF*/ 0xAE,//关闭显示 0xD5,//设置时钟分频因子,震荡频率 0x80, //[3:0],分频因子;[7:4],震荡频率
0xA8,//设置驱动路数 0X3F,//默认0X3F(1/64) 0xD3,//设置显示偏移 0X00,//默认为0 0x40,//设置显示开始行 [5:0],行数. 0x8D,//电荷泵设置 0x14,//bit2,开启/关闭 0x20,//设置内存地址模式 0x02,//[1:0],00,列地址模式;01,行地址模式;10,页地址模式;默认10; 0xA1,//段重定义设置,bit0:0,0->0;1,0->127; 0xC8,//设置COM扫描方向;bit3:0,普通模式;1,重定义模式 COM[N-1]->COM0;N:驱动路数 0xDA,//设置COM硬件引脚配置 0x12,//[5:4]配置 0x81,//对比度设置 0xEF,//1~255;默认0X7F (亮度设置,越大越亮) 0xD9,//设置预充电周期 0xf1,//[3:0],PHASE 1;[7:4],PHASE 2; 0xDB,//设置VCOMH 电压倍率 0x30,//[6:4] 000,0.65*vcc;001,0.77*vcc;011,0.83*vcc; 0xA4,//全局显示开启;bit0:1,开启;0,关闭;(白屏/黑屏) 0xA6,//设置显示方式;bit0:1,反相显示;0,正常显示 0xAF,//开启显示 };
|
(5)屏幕初始化后,可以选择清除屏幕或者填充屏幕。
填充屏幕,主要是让屏幕全部点亮。通过代码,我们知道有两个步骤,填充page(页)数,和Column(列)数。
OLED屏幕像素为128*64,每一页page有8行,一共8页。124列。
(6)向屏幕写入数据:I2C开始—写入0x40—写入数据—I2C结束。
填充屏幕写入的数据为:data=0xFF
清除屏幕写入数据为: data=0x00
/oled 屏幕填充 void OLED_full(void) { unsigned char page,column; for(page=0;page<8;page++) //page loop { Page_set(page); Column_set(0); for(column=0;column<128;column++) //column loop { OLED_send_data(0xff); } } } //向 oled 发送数据 void OLED_send_data(unsigned char o_data) { IIC_start(); IIC_write(0x40); IIC_write(o_data); IIC_stop(); }
//设置行数 void Column_set(unsigned char column) { OLED_send_cmd(0x10|(column>>4)); //设置列地址高位 OLED_send_cmd(0x00|(column&0x0f)); //设置列地址低位
} //设置页数 void Page_set(unsigned char page) { OLED_send_cmd(0xb0+page); } |
2.2 OLED屏幕工作总结:
(1)Main函数中:IO初始化—OLED初始化—OLED填充—图片轮流显示
(2)OLED屏幕初始化函数如下,主要是向屏幕模组写入25个初始化命令。
OLED_init(void)-- OLED_send_cmd(OLED_init_cmd[i])。
(3)向屏幕写入命令:I2C开始—写入0x00—写入命令(Command)—I2C结束。
(4)初始化屏幕的命令有25个。每个命令8bit,具体每个命令的作用在代码中有详细的中文介绍。
(5)屏幕初始化后,可以选择清除屏幕或者填充屏幕。
填充屏幕,主要是让屏幕全部点亮。通过代码,我们知道有两个步骤,填充page(页)数,和Column(列)数。
OLED屏幕像素为128*64,每一页page有8行,一共8页。124列。
(6)向屏幕写入数据:I2C开始—写入0x40—写入数据(data)—I2C结束。
填充屏幕写入的数据为:data=0xFF
清除屏幕写入数据为: data=0x00
(7)要屏幕显示其他内容,如数字,字符等,可以用字模提取软件进行转换,将特定特定汉字图片转换成16进制的data数据。下图是部分的1206字符大小的data数据,有专门的C文件可以可以直接用,这个不用担心。
至此OLED工作流程基本ok。接下来就是移植到Nordic蓝牙芯片上。
3. nRF52832蓝牙芯片上开发I2C的OLED屏幕
3.1 Nordic I2C接口
关于Noridc蓝牙芯片的I2C接口,之前的文章有单独详细介绍,请自行翻阅查看。
移植的困难点主要在重构 向OLED屏幕写入命令和写入数据这两个函数上。
通过多次调试,确定了一下代码最适用。
具体的Nordic I2C实战应用,在前一篇SHT3x温湿度的文章有单独介绍过,
/**
* 描 述 : 向OLED写入1字节命令或数据
* 入 参 : dat:数据;mode:=0:写入命令,=1:写入数据
* 返回值 : 无
**/
void OLED_Write_Command(uint8_t command)
{
ret_code_t err_code;
uint8_t command_send[2] = { 0x00,command};
uint8_t retry_num = 50;
do{
err_code = nrf_drv_twi_tx(&m_twi, OLED096_ADDRESS, command_send, 2, false);
retry_num--;
//等待TWI总线应答
//UNUSED_VARIABLE(err_code);
}
while((NRF_SUCCESS != err_code) && (0 < retry_num));
}
//oled write data
void OLED_Write_Data(unsigned char o_data)
{
ret_code_t err_code;
uint8_t dta_send[2] = { 0x40,o_data};
uint8_t retry_num = 50;
do{
err_code = nrf_drv_twi_tx(&m_twi, OLED096_ADDRESS, dta_send, 2, false);
retry_num--;
}
while ((NRF_SUCCESS != err_code) && (0 < retry_num));
}
/**
* @brief Writes an byte to the display data ram or the command register
*
* @param [in] chData Data to be writen to the display data ram or the command register
* @param [in] chCmd 0: Writes to the command register
* 1: Writes to the display data ram
* @return None
*/
void OLED_Write_byte(uint8_t chData, uint8_t chCmd)
{
if(chCmd){ //write data
OLED_Write_Data(chData);
}
else{ //write command
OLED_Write_Command(chCmd);
}
}
3.2 OLED显示字符和数字等函数
/**
* @brief Brief
* chMod:0,反白显示;1,正常显示。 size:选择字体16/12
* @param [in] chXpos Specifies the X position ,0-127
* @param [in] chYpos Specifies the Y position ,0-63
* @param [in] chChr a character
* @param [in] chSize character of size
* @param [in] chMode character of mode
* @retval None
*/
void OLED_display_char(uint8_t chXpos, uint8_t chYpos, uint8_t chChr, uint8_t chSize, uint8_t chMode)
{
uint8_t i, j;
uint8_t chTemp, chYpos0 = chYpos;
chChr = chChr - ' '; //得到偏移后的值
for (i = 0; i < chSize; i ++)
{
if (chSize == 12) //调用1206字体
{
if (chMode)
{
chTemp = c_chFont1206[chChr][i];
}
else
{
chTemp = ~c_chFont1206[chChr][i];
}
}
else//调用1608字体
{
if (chMode)
{
chTemp = c_chFont1608[chChr][i];
}
else
{
chTemp = ~c_chFont1608[chChr][i];
}
}
for (j = 0; j < 8; j ++)
{
if (chTemp & 0x80)
{
OLED_draw_point(chXpos, chYpos, 1);
}
else
{
OLED_draw_point(chXpos, chYpos, 0);
}
chTemp <<= 1;
chYpos ++;
if ((chYpos - chYpos0) == chSize)
{
chYpos = chYpos0;
chXpos ++;
break;
}
}
}
}
/**
* @brief Brief
* 显示2个数字
* @param [in] chXpos Parameter_Description
* @param [in] chYpos Parameter_Description
* @param [in] chNum Parameter_Description,数值
* @param [in] chLen Parameter_Description,数字的位数
* @param [in] chSize Parameter_Description,字体大小
* @return Return_Description
*
* @details Details
*/
void OLED_display_num(uint8_t chXpos, uint8_t chYpos, uint32_t chNum, uint8_t chLen, uint8_t chSize)
{
uint8_t i;
uint8_t chTemp, chShow = 0;
for(i = 0; i < chLen; i ++)
{
chTemp = (chNum / OLED_pow(10, chLen - i - 1)) % 10;
if(chShow == 0 && i < (chLen - 1))
{
if(chTemp == 0)
{
OLED_display_char(chXpos + (chSize / 2) * i, chYpos, ' ', chSize, 1);
continue;
}
else
{
chShow = 1;
}
}
OLED_display_char(chXpos + (chSize / 2) * i, chYpos, chTemp + '0', chSize, 1);
}
}
/**
* @brief Displays a string on the screen
* 显示字符串,*p:字符串起始地址
* @param [in] chXpos Specifies the X position
* @param [in] chYpos Specifies the Y position
* @param [in] pchString Pointer to a string to display on the screen
* @param [in] chSize
* @param [in] chMode
* @return None
*/
void OLED_display_string(uint8_t chXpos, uint8_t chYpos, const uint8_t *pchString, uint8_t chSize, uint8_t chMode)
{
while (*pchString != '\0')
{
if (chXpos > (X_WIDTH - chSize / 2))
{
chXpos = 0;
chYpos += chSize;
if (chYpos > (Y_HEIGHT - chSize))
{
chYpos = chXpos = 0;
OLED_clear_screen(0x00);
}
}
OLED_display_char(chXpos, chYpos, *pchString, chSize, chMode);
chXpos += chSize / 2;
pchString ++;
}
}
4、结果展示
nRF52832蓝牙芯片上用4pin的I2C OLED屏幕显示温湿度:
更多的项目代码资源可以关注公众号,或在公众号内加客服微信,获取项目帮助。
白浪介绍:
(1)关于射频、微波、天线、无线通信、智能硬件、软件编程、渗透安全、人工智能、区块链,Java、Android、C/C++、python等综合能力的培养提升。
(2)各种学习资料、学习软件分享。
1.扫码关注公众号(Geekxiaobai)
2. 如在后台发送“Python高级编程”“Python Graphics”或者“2003”,即可免费获得电子书籍。仅供学习之用。
3. 扫码关注后,查看往期内容,会有更多资料惊喜等着你来拿哦
想要更多相关学习资料,可以在文章后面留言哦。
========******=========******========******=========******==========