经过长时间的尝试,下载功能终于又恢复了,起初以为是下载器过于脆弱,现在终于明白所配的杜邦线才是真正的元凶,4根线中为独黄线出现了断线,如果按序使用的话无论你怎么连也无法跳开异常。恢复了下载功能,就先从OLED屏的显示驱动入手开始测试。
为了减少失败的风险,所选的OLED屏是一款0.96寸的准双色屏,其显示分辨率为128*64像素点。该显示屏以I2C的接口方式工作,可以GPIO来模拟I2C来驱动它。
为节省资源,这里直接使用的LED1和LED2所使用的引脚,只需打开LED与相关引脚的连接即可。
OLED屏与开发板的具体连接关系为:
SCL--- PB4
SDA---PB4
为输出高低电平,所进行的定义为:
#defineSCL_highgpio_set_level(GPIO_PB4,1)
#defineSCL_lowgpio_set_level(GPIO_PB4,0)
#defineSDA_highgpio_set_level(GPIO_PB5,1)
#defineSDA_lowgpio_set_level(GPIO_PB5,0)
由于MCU的处理速度较高,为此在输出高低电平时需添加适当的延时,否则将无法使OLED屏工作。以I2C的开始与结束函数为例,其内容如下:
voidIIC_Start(){ SCL_high; delay_us(2); SDA_high; delay_us(2); SDA_low; delay_us(2); SCL_low; delay_us(2); } voidIIC_Stop() { SCL_low; delay_us(2); SDA_low; delay_us(2); SCL_high; delay_us(2); SDA_high; delay_us(2); }
复制代码以模拟方式实现I2C发送字节数据的函数为:
void Write_IIC_Byte(unsignedcharIIC_Byte){ unsignedchari; unsignedcharm,da; da=IIC_Byte; SCL_low; for(i=0;i<8;i++) { m=da; m=m&0x80; if(m==0x80) { SDA_high; } elseSDA_low; da=da<<1; delay_us(2); SCL_high; delay_us(2); SCL_low; delay_us(2); } }
复制代码OLED屏的初始化函数为:
voidOLED_Init(void){ OLED_WR_Byte(0xAE,OLED_CMD); OLED_WR_Byte(0x02,OLED_CMD); OLED_WR_Byte(0x10,OLED_CMD); OLED_WR_Byte(0x40,OLED_CMD); OLED_WR_Byte(0x81,OLED_CMD); OLED_WR_Byte(0xff,OLED_CMD); OLED_WR_Byte(0xA1,OLED_CMD); OLED_WR_Byte(0xC8,OLED_CMD); OLED_WR_Byte(0xA6,OLED_CMD); OLED_WR_Byte(0xA8,OLED_CMD); OLED_WR_Byte(0x3f,OLED_CMD); OLED_WR_Byte(0xD3,OLED_CMD); OLED_WR_Byte(0x00,OLED_CMD); OLED_WR_Byte(0xd5,OLED_CMD); OLED_WR_Byte(0x80,OLED_CMD); OLED_WR_Byte(0xD9,OLED_CMD); OLED_WR_Byte(0xF1,OLED_CMD); OLED_WR_Byte(0xDA,OLED_CMD); OLED_WR_Byte(0x12,OLED_CMD); OLED_WR_Byte(0xDB,OLED_CMD); OLED_WR_Byte(0x40,OLED_CMD); OLED_WR_Byte(0x20,OLED_CMD); OLED_WR_Byte(0x02,OLED_CMD); OLED_WR_Byte(0x8D,OLED_CMD); OLED_WR_Byte(0x14,OLED_CMD); OLED_WR_Byte(0xA4,OLED_CMD); OLED_WR_Byte(0xA6,OLED_CMD); OLED_WR_Byte(0xAF,OLED_CMD); OLED_WR_Byte(0xAF,OLED_CMD); OLED_Clear(); OLED_Set_Pos(0,0); }
复制代码实现OLED屏清除效果的函数为:
void OLED_Clear(void){ unsignedchari,n; for(i=0;i<8;i++) { OLED_WR_Byte (0xb0+i,OLED_CMD); OLED_WR_Byte (0x00,OLED_CMD); OLED_WR_Byte (0x10,OLED_CMD); for(n=0;n<128;n++) OLED_WR_Byte(0x00,OLED_DATA); } }
复制代码在字库的配合下,实现字符显示的函数为:
voidOLED_ShowChar(unsignedcharx,unsignedchary,unsignedcharchr,unsignedcharChar_Size){ unsignedchar c=0,i=0; c=chr-' '; if(Char_Size ==16) { OLED_Set_Pos(x,y); for(i=0;i<8;i++) OLED_WR_Byte(F8X16[c*16+i],OLED_DATA); OLED_Set_Pos(x,y+1); for(i=0;i<8;i++) OLED_WR_Byte(F8X16[c*16+i+8],OLED_DATA); } }
复制代码实现数值显示的函数为:
voidOLED_ShowNum(unsignedcharx,unsignedchary,longintnum,unsignedcharlen,unsignedchar size2){ unsignedchart,temp; unsignedcharenshow=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+(size2/2)*t,y,' ',size2); continue; } elseenshow=1; } OLED_ShowChar(x+(size2/2)*t,y,temp+'0',size2); } }
复制代码比较令人差异的是移植字符串显示函数时,却一直无法完成编译,问题一直定位在指针变量上,难道Telink B91或其开发工具不支持该数据类型?没办法,在用到字符串显示时只好靠字符来码了!当然,还有一种方法就是以数组来替代指针的使用。实现测试效果的主程序为:
intmain (void){ sys_init(LDO_1P4_LDO_1P8, VBAT_MAX_VALUE_GREATER_THAN_3V6); user_read_flash_value_calib(); CCLK_24M_HCLK_24M_PCLK_24M; user_init(); OLED_Init(); OLED_Clear(); OLED_ShowChar(20,0,'T',16); OLED_ShowChar(28,0,'e',16); OLED_ShowChar(36,0,'l',16); OLED_ShowChar(44,0,'i',16); OLED_ShowChar(52,0,'n',16); OLED_ShowChar(60,0,'k',16); OLED_ShowChar(76,0,'B',16); OLED_ShowNum(84,0,91,2,16); OLED_ShowCHinese(20,2,3); OLED_ShowCHinese(36,2,4); OLED_ShowCHinese(52,2,5); while (1) { delay_ms(1000); gpio_toggle(LED3); gpio_toggle(LED4); } return 0; }
复制代码OLED屏显示效果图