连续两个月的加班,给ODM客户生产温控器订单,今天终于顺利发货,对于工程师出身的我,终于可以对着电脑,消停几天,研究技术,分享技术了,闲话少说,直接进入正题:
半年前有个老客户介绍个中央某院的项目,我主业是做各种温控器的,老客户介绍的新客户,没法推脱,就干吧,项目需求具体细节不方便公开,说说本次要分享的部分,要实现的功能是一个OLED任意显示一段中文句子。
项目的硬件组成比较简单:STM8L051+ KEY + OLED + GT20L16S1Y
软件平台:IAR
整个项目没什么难点,但没做过这个的,也需要一番折腾,在这里,我把项目的主要代码贴出来供电友们参考,也感谢之前版本的电友。做个靠谱的电友,除了分享单独的.c.h驱动文件,最后还会有调用伪代码,也就是整个代码的调用过程。
一:高通字库芯片驱动程序:
#include "stm8l15x.h"//STM8L051/151等系列共用库函数 #define S1Y_CLK_L (GPIO_ResetBits(GPIOB,GPIO_Pin_4)) #define S1Y_CLK_H (GPIO_SetBits(GPIOB,GPIO_Pin_4)) #define S1Y_CS_L (GPIO_ResetBits(GPIOB,GPIO_Pin_5)) #define S1Y_CS_H (GPIO_SetBits(GPIOB,GPIO_Pin_5)) #define S1Y_SI_L (GPIO_ResetBits(GPIOB,GPIO_Pin_6)) #define S1Y_SI_H (GPIO_SetBits(GPIOB,GPIO_Pin_6)) #define S1Y_SO GPIO_ReadInputDataBit(GPIOB, GPIO_Pin_7) GPIO_Init(GPIOB, GPIO_Pin_4, GPIO_Mode_Out_PP_Low_Fast); //高速推挽输出低电平[SCLK] GPIO_Init(GPIOB, GPIO_Pin_5, GPIO_Mode_Out_PP_Low_Fast); //高速推挽输出低电平[CS] GPIO_Init(GPIOB, GPIO_Pin_6, GPIO_Mode_Out_PP_Low_Fast); //高速推挽输出低电平[SI] GPIO_Init(GPIOB, GPIO_Pin_7, GPIO_Mode_In_PU_No_IT); //上拉输入[SO] /*************************************** ASCIICode:表示ASCII 码(8bits) ****************************************/ u8 S1Y_ASCII_GetData( u8 ASCIICode, u32 BaseAdd, u8* S1YDZ_Data ) if( ( ASCIICode >= 0x20 ) && ( ASCIICode <= 0x7e ) ) S1Y_rdat_bat( ( ASCIICode - 0x20 ) * 8 + BaseAdd, 8, S1YDZ_Data ); //5X7 S1Y_rdat_bat( ( ASCIICode - 0x20 ) * 8 + BaseAdd, 8, S1YDZ_Data ); //7X8 S1Y_rdat_bat( ( ASCIICode - 0x20 ) * 16 + BaseAdd, 16, S1YDZ_Data ); //8X16 A S1Y_rdat_bat( ( ASCIICode - 0x20 ) * 26 + BaseAdd, 16, S1YDZ_Data ); //8X16 F S1Y_rdat_bat( ( ASCIICode - 0x20 ) * 34 + BaseAdd + 2, 32, S1YDZ_Data ); //16X16 Arial S1Y_rdat_bat( ( ASCIICode - 0x20 ) * 34 + BaseAdd + 2, 32, S1YDZ_Data ); //16X16 T /*************************************************** MSB 表示汉字内码GBCode 的高8bits。 LSB 表示汉字内码GBCode 的低8bits。 Address 表示汉字或ASCII字符点阵在芯片中的字节地址。 BaseAdd:说明点阵数据在字库芯片中的起始地址。 *****************************************************/ void S1Y_gt16_GetData( u8 MSB, u8 LSB, u8* S1YDZ_Data ) u32 temp = ( MSB - 0xB0 ) * 94 + LSB - 0xA1; u32 BaseAdd = 0, Address; if( MSB == 0xA9 && LSB >= 0xA1 ) Address = ( 282 + ( LSB - 0xA1 ) ) * 32 + BaseAdd; else if( MSB >= 0xA1 && MSB <= 0xA3 && LSB >= 0xA1 ) Address = ( ( MSB - 0xA1 ) * 94 + ( LSB - 0xA1 ) ) * 32 + BaseAdd; else if( MSB >= 0xB0 && MSB <= 0xF7 && LSB >= 0xA1 ) Address = ( 846 + temp ) * 32 + BaseAdd; S1Y_rdat_bat( Address, 32, S1YDZ_Data ); //Address=((MSB-0xB0)*94+(LSB-0xA1)+846)*32+BaseAdd; /**************************************************** BaseAdd:说明本套字库在字库芯片中的起始字节地址。 *****************************************************/ void S1Y_GB_EXT_816( u16 FontCode, u8* S1YDZ_Data ) u32 BaseAdd = 0x3b7d0, Address; u32 temp1 = ( FontCode - 0xAAA1 ); u32 temp2 = ( FontCode - 0xABA1 + 95 ); if( FontCode >= 0xAAA1 && FontCode <= 0xAAFE ) Address = temp1 * 16 + BaseAdd; else if( FontCode >= 0xABA1 && FontCode <= 0xABC0 ) Address = temp2 * 16 + BaseAdd; S1Y_rdat_bat( Address, 16, S1YDZ_Data ); /**************************************************** Address : 表示字符点阵在芯片中的字节地址。 *****************************************************/ u8 S1Y_rdat_bat( u32 address, u8 byte_long, u8* p_arr ) for( j = 0; j < byte_long; j++ ) p_arr[j] = S1Y_ReadByte(); void S1Y_SendByte( u32 cmd ) for( i = 0; i < 32; i++ ) //-------------------------------------分割线--------------------------------- void S1Y_SendByte(u32 cmd); u8 S1Y_rdat_bat(u32 address,u8 byte_long,u8 *p_arr); u8 S1Y_ASCII_GetData(u8 ASCIICode,u32 BaseAdd,u8 *S1YDZ_Data); void S1Y_gt16_GetData (u8 MSB,u8 LSB,u8 *S1YDZ_Data); void S1Y_GB_EXT_816(u16 FontCode,u8 *S1YDZ_Data);
OLED显示就比较简单了,显示任意汉字字符串,也折腾了我几根头发,下面也贴出来分享一下:
void delay_ms( unsigned int ms ) void OLED_ColorTurn( u8 i ) OLED_WR_Byte( 0xA6, OLED_CMD ); //正常显示 OLED_WR_Byte( 0xA7, OLED_CMD ); //反色显示 void OLED_DisplayTurn( u8 i ) OLED_WR_Byte( 0xC8, OLED_CMD ); //正常显示 OLED_WR_Byte( 0xA1, OLED_CMD ); OLED_WR_Byte( 0xC0, OLED_CMD ); //反转显示 OLED_WR_Byte( 0xA0, OLED_CMD ); void I2C_WaitAck( void ) //测数据信号的电平 OLED_SCL_Clr();//将时钟信号设置为低电平 if( dat & 0x80 ) //将dat的8位从最高位依次写入 //mode:数据/命令标志 0,表示命令;1,表示数据; void OLED_WR_Byte( u8 dat, u8 mode ) void OLED_Set_Pos( u8 x, u8 y ) OLED_WR_Byte( 0xb0 + y, OLED_CMD ); OLED_WR_Byte( ( ( x & 0xf0 ) >> 4 ) | 0x10, OLED_CMD ); OLED_WR_Byte( ( x & 0x0f ), OLED_CMD ); 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 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 //清屏函数,清完屏,整个屏幕是黑色的!和没点亮一样!!! 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 ); void OLED_ShowChar( u8 x, u8 y, u8 chr, u8 sizey ) u8 c = 0, sizex = sizey / 2; size1 = ( sizey / 8 + ( ( sizey % 8 ) ? 1 : 0 ) ) * ( sizey / 2 ); for( i = 0; i < size1; i++ ) if( i % sizex == 0 && sizey != 8 ) OLED_WR_Byte( asc2_0806[c][i], OLED_DATA ); //6X8字号 OLED_WR_Byte( asc2_1608[c][i], OLED_DATA ); //8x16字号 // else if(sizey==xx) OLED_WR_Byte(asc2_xxxx[c][i],OLED_DATA);//用户添加字号 u32 oled_pow( u8 m, u8 n ) void OLED_ShowNum( u8 x, u8 y, u32 num, u8 len, u8 sizey ) for( t = 0; t < len; t++ ) temp = ( num / oled_pow( 10, len - t - 1 ) ) % 10; if( enshow == 0 && t < ( len - 1 ) ) OLED_ShowChar( x + ( sizey / 2 + m )*t, y, ' ', sizey ); OLED_ShowChar( x + ( sizey / 2 + m )*t, y, temp + '0', sizey ); void OLED_ShowString( u8 x, u8 y, u8* chr, u8 sizey ) OLED_ShowChar( x, y, chr[j++], sizey ); void OLED_ShowChinese( u8 x, u8 y, u8 *temp, u8 sizey ) u16 i, size1 = ( sizey / 8 + ( ( sizey % 8 ) ? 1 : 0 ) ) * sizey; for( i = 0; i < size1; i++ ) OLED_WR_Byte( temp[i], OLED_DATA ); //16x16字号 // else if(sizey==xx) OLED_WR_Byte(xxx[c][i],OLED_DATA);//用户添加字号 //---------------------------------------------------------- void OLED_ShowGB2312(unsigned char x,unsigned char y,unsigned char textH,unsigned char textL) unsigned char fontbuf[32]; S1Y_gt16_GetData(textH,textL,fontbuf); OLED_ShowChinese( x, y, fontbuf, 16 ); // OLED_WR_Byte(fontbuf[t],OLED_DATA); // OLED_WR_Byte(fontbuf[t+16],OLED_DATA); void OLED_ShowStr(unsigned char x,unsigned char y,unsigned char* text) if(((text[i]>=0xb0) &&(text[i]<=0xf7))&&(text[i+1]>=0xa1)) OLED_ShowGB2312(x,y,text[i],text[i+1]); else if((text[i]>=0x20) && (text[i]<=0x7e)) //OLED_ShowASCII(x,y,text[i]); //-------------------------------------------------------------------- void OLED_DrawBMP( u8 x, u8 y, u8 sizex, u8 sizey, u8 BMP[] ) sizey = sizey / 8 + ( ( sizey % 8 ) ? 1 : 0 ); for( i = 0; i < sizey; i++ ) OLED_Set_Pos( x, i + y ); for( m = 0; m < sizex; m++ ) OLED_WR_Byte( BMP[j++], OLED_DATA ); GPIO_Init( OLED_PORT,OLED_SCL,GPIO_Mode_Out_PP_High_Fast ); GPIO_Init( OLED_PORT,OLED_SDA,GPIO_Mode_Out_PP_High_Fast ); OLED_WR_Byte( 0xAE, OLED_CMD ); /*display off*/ OLED_WR_Byte( 0x00, OLED_CMD ); /*set lower column address*/ OLED_WR_Byte( 0x10, OLED_CMD ); /*set higher column address*/ OLED_WR_Byte( 0x00, OLED_CMD ); /*set display start line*/ OLED_WR_Byte( 0xB0, OLED_CMD ); /*set page address*/ OLED_WR_Byte( 0x81, OLED_CMD ); /*contract control*/ OLED_WR_Byte( 0xff, OLED_CMD ); /*128*/ OLED_WR_Byte( 0xA1, OLED_CMD ); /*set segment remap*/ OLED_WR_Byte( 0xA6, OLED_CMD ); /*normal / reverse*/ OLED_WR_Byte( 0xA8, OLED_CMD ); /*multiplex ratio*/ OLED_WR_Byte( 0x1F, OLED_CMD ); /*duty = 1/32*/ OLED_WR_Byte( 0xC8, OLED_CMD ); /*Com scan direction*/ OLED_WR_Byte( 0xD3, OLED_CMD ); /*set display offset*/ OLED_WR_Byte( 0x00, OLED_CMD ); OLED_WR_Byte( 0xD5, OLED_CMD ); /*set osc division*/ OLED_WR_Byte( 0x80, OLED_CMD ); OLED_WR_Byte( 0xD9, OLED_CMD ); /*set pre-charge period*/ OLED_WR_Byte( 0x1f, OLED_CMD ); OLED_WR_Byte( 0xDA, OLED_CMD ); /*set COM pins*/ OLED_WR_Byte( 0x00, OLED_CMD ); OLED_WR_Byte( 0xdb, OLED_CMD ); /*set vcomh*/ OLED_WR_Byte( 0x40, OLED_CMD ); OLED_WR_Byte( 0x8d, OLED_CMD ); /*set charge pump enable*/ OLED_WR_Byte( 0x14, OLED_CMD ); OLED_WR_Byte( 0xAF, OLED_CMD ); /*display ON*/ //-----------------------------------分割线------------------------------------------ #include "stm8l15x.h"//STM8L051/151等系列共用库函数 #define OLED_PORT GPIOC//SCL //#define OLED_SCL GPIO_Pin_1//SCL //#define OLED_SDA GPIO_Pin_0//SDA #define OLED_SCL GPIO_Pin_0//SCL #define OLED_SDA GPIO_Pin_1//SDA //-----------------OLED端口定义---------------- #define OLED_SCL_Clr() GPIO_ResetBits(OLED_PORT, OLED_SCL)//SCL IIC接口的数据信号 #define OLED_SCL_Set() GPIO_SetBits(OLED_PORT, OLED_SCL) #define OLED_SDA_Clr() GPIO_ResetBits(OLED_PORT, OLED_SDA )//SDA IIC接口的时钟信号 #define OLED_SDA_Set() GPIO_SetBits(OLED_PORT, OLED_SDA ) //-------------------------------------------------- void delay_ms(unsigned int ms); void OLED_ColorTurn(u8 i); void OLED_DisplayTurn(u8 i); void OLED_WR_Byte(u8 dat,u8 cmd); void OLED_Set_Pos(u8 x, u8 y); void OLED_Display_On(void); void OLED_Display_Off(void); void OLED_ShowChar(u8 x,u8 y,u8 chr,u8 sizey); void OLED_ShowNum(u8 x,u8 y,u32 num,u8 len,u8 sizey); void OLED_ShowString(u8 x,u8 y,u8 *chr,u8 sizey); //void OLED_ShowChinese(u8 x,u8 y,u8 no,u8 sizey); void OLED_ShowChinese( u8 x, u8 y, u8 *temp, u8 sizey ); void OLED_DrawBMP(u8 x,u8 y,u8 sizex, u8 sizey,u8 BMP[]); void OLED_ShowStr(unsigned char x,unsigned char y,unsigned char* text);
最后是调用过程伪代码:
OLED_ShowStr( 0, 0, tab[HZ] );// tab[]里面存放的是汉字字符串,例如:"华温冷链巴拉巴拉"
最后的最后,刚忙完,写博客的时候有点累,有任何不明白的地方,欢迎一起探讨 QQ741684134。PS:遇到很多网友找我聊很基础的单片机应用问题,请自行百度,因为实在很忙。
|