使用u8g2 使用硬件iic驱动某些page为4个字节 带灰度的lcd显示屏幕的时候有时候只显示上半部,下半部不显示,例如uc1617等。
原因:
以uc1617为例,链接https://github.com/olikraus/u8g2/blob/master/csrc/u8x8_d_uc1617.c
在u8x8_d_uc1617_common方法中的case U8X8_MSG_DISPLAY_DRAW_TILE分支
uint8_t u8x8_d_uc1617_common(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{uint8_t x, y, c, a;uint8_t *ptr;switch(msg){case U8X8_MSG_DISPLAY_DRAW_TILE:u8x8_cad_StartTransfer(u8x8);y = ((u8x8_tile_t *)arg_ptr)->y_pos;y*=2;x = ((u8x8_tile_t *)arg_ptr)->x_pos;x *= 8;x += u8x8->x_offset;u8x8_cad_SendCmd(u8x8, 0x060 | (x&15));u8x8_cad_SendCmd(u8x8, 0x070 | (x>>4)); u8x8_cad_SendCmd(u8x8, 0x00 | (y));#ifdef NOT_REQUIREDu8x8_cad_SendCmd(u8x8, 0xf8 ); /* disable window */u8x8_cad_SendCmd(u8x8, 0xf4 ); /* page start */u8x8_cad_SendCmd(u8x8, y ); u8x8_cad_SendCmd(u8x8, 0xf5 ); /* x start */u8x8_cad_SendCmd(u8x8, x ); u8x8_cad_SendCmd(u8x8, 0xf6 ); /* page end */u8x8_cad_SendCmd(u8x8, y ); u8x8_cad_SendCmd(u8x8, 0xf7 ); /* x end */u8x8_cad_SendCmd(u8x8, 127 ); u8x8_cad_SendCmd(u8x8, 0xf9 ); /* enable window */
#endifa = arg_int;do{c = ((u8x8_tile_t *)arg_ptr)->cnt;ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;do{u8x8_cad_SendData(u8x8, 8, u8x8_convert_tile_for_uc1617_lower4bit(ptr));ptr += 8;x += 8;c--;} while( c > 0 ); a--;} while( a > 0 );x = ((u8x8_tile_t *)arg_ptr)->x_pos;x *= 8;x += u8x8->x_offset;u8x8_cad_SendCmd(u8x8, 0x060 | (x&15));u8x8_cad_SendCmd(u8x8, 0x070 | (x>>4)); u8x8_cad_SendCmd(u8x8, 0x00 | (y+1));a = arg_int;do{c = ((u8x8_tile_t *)arg_ptr)->cnt;ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;do{u8x8_cad_SendData(u8x8, 8, u8x8_convert_tile_for_uc1617_upper4bit(ptr));ptr += 8;x += 8;c--;} while( c > 0 ); a--;} while( a > 0 );u8x8_cad_EndTransfer(u8x8);break;case U8X8_MSG_DISPLAY_SET_POWER_SAVE:if ( arg_int == 0 )u8x8_cad_SendSequence(u8x8, u8x8_d_uc1617_powersave0_seq);elseu8x8_cad_SendSequence(u8x8, u8x8_d_uc1617_powersave1_seq);break;case U8X8_MSG_DISPLAY_SET_FLIP_MODE:if ( arg_int == 0 ){u8x8_cad_SendSequence(u8x8, u8x8_d_uc1617_flip0_seq);u8x8->x_offset = u8x8->display_info->default_x_offset;}else{u8x8_cad_SendSequence(u8x8, u8x8_d_uc1617_flip1_seq);u8x8->x_offset = u8x8->display_info->flipmode_x_offset;} break;
#ifdef U8X8_WITH_SET_CONTRASTcase U8X8_MSG_DISPLAY_SET_CONTRAST:u8x8_cad_StartTransfer(u8x8);u8x8_cad_SendCmd(u8x8, 0x081 );u8x8_cad_SendArg(u8x8, arg_int ); /* uc1617 has range from 0 to 255 */u8x8_cad_EndTransfer(u8x8);break;
#endifdefault:return 0;}return 1;
}
在往lcd显示屏写写数据的时候,先用命令写显示地址,再写数据,命令和数据的区别在于iic地址不同,例如写命令使用iic地址0x78,写数据使用iic地址0x79,具体根据不同lcd数据手册iic地址有所不同。上面的分支U8X8_MSG_DISPLAY_DRAW_TILE作用是向lcd先写地址,再写数据,在这个分支中,只有一个u8x8_cad_StartTransfer与u8x8_cad_EndTransfer包含整个方法。
u8x8_cad_EndTransfer用于产生一个iic终止信号,代表操作完成
而在这个方法中,有2个写不同iic地址的行为,但是只产生了一个终止信号,导致可能后半部分无效,所以只显示半面。
解决方案:
添加多个u8x8_cad_StartTransfer与u8x8_cad_EndTransfer。
把对一个地址的操作行为用u8x8_cad_StartTransfer与u8x8_cad_EndTransfer包含起来
例如:
uint8_t u8x8_d_uc1617_common(u8x8_t *u8x8, uint8_t msg, uint8_t arg_int, void *arg_ptr)
{uint8_t x, y, c, a;uint8_t *ptr;switch(msg){case U8X8_MSG_DISPLAY_DRAW_TILE:u8x8_cad_StartTransfer(u8x8);y = ((u8x8_tile_t *)arg_ptr)->y_pos;y*=2;x = ((u8x8_tile_t *)arg_ptr)->x_pos;x *= 8;x += u8x8->x_offset;u8x8_cad_SendCmd(u8x8, 0x060 | (x&15));u8x8_cad_SendCmd(u8x8, 0x070 | (x>>4)); u8x8_cad_SendCmd(u8x8, 0x00 | (y));#ifdef NOT_REQUIREDu8x8_cad_SendCmd(u8x8, 0xf8 ); /* disable window */u8x8_cad_SendCmd(u8x8, 0xf4 ); /* page start */u8x8_cad_SendCmd(u8x8, y ); u8x8_cad_SendCmd(u8x8, 0xf5 ); /* x start */u8x8_cad_SendCmd(u8x8, x ); u8x8_cad_SendCmd(u8x8, 0xf6 ); /* page end */u8x8_cad_SendCmd(u8x8, y ); u8x8_cad_SendCmd(u8x8, 0xf7 ); /* x end */u8x8_cad_SendCmd(u8x8, 127 ); u8x8_cad_SendCmd(u8x8, 0xf9 ); /* enable window */
#endifa = arg_int;do{c = ((u8x8_tile_t *)arg_ptr)->cnt;ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;do{u8x8_cad_SendData(u8x8, 8, u8x8_convert_tile_for_uc1617_lower4bit(ptr));ptr += 8;x += 8;c--;} while( c > 0 ); a--;} while( a > 0 );
// 下面这2行是添加的
u8x8_cad_EndTransfer(u8x8);
u8x8_cad_StartTransfer(u8x8);x = ((u8x8_tile_t *)arg_ptr)->x_pos;x *= 8;x += u8x8->x_offset;u8x8_cad_SendCmd(u8x8, 0x060 | (x&15));u8x8_cad_SendCmd(u8x8, 0x070 | (x>>4)); u8x8_cad_SendCmd(u8x8, 0x00 | (y+1));a = arg_int;do{c = ((u8x8_tile_t *)arg_ptr)->cnt;ptr = ((u8x8_tile_t *)arg_ptr)->tile_ptr;do{u8x8_cad_SendData(u8x8, 8, u8x8_convert_tile_for_uc1617_upper4bit(ptr));ptr += 8;x += 8;c--;} while( c > 0 ); a--;} while( a > 0 );u8x8_cad_EndTransfer(u8x8);break;case U8X8_MSG_DISPLAY_SET_POWER_SAVE:if ( arg_int == 0 )u8x8_cad_SendSequence(u8x8, u8x8_d_uc1617_powersave0_seq);elseu8x8_cad_SendSequence(u8x8, u8x8_d_uc1617_powersave1_seq);break;case U8X8_MSG_DISPLAY_SET_FLIP_MODE:if ( arg_int == 0 ){u8x8_cad_SendSequence(u8x8, u8x8_d_uc1617_flip0_seq);u8x8->x_offset = u8x8->display_info->default_x_offset;}else{u8x8_cad_SendSequence(u8x8, u8x8_d_uc1617_flip1_seq);u8x8->x_offset = u8x8->display_info->flipmode_x_offset;} break;
#ifdef U8X8_WITH_SET_CONTRASTcase U8X8_MSG_DISPLAY_SET_CONTRAST:u8x8_cad_StartTransfer(u8x8);u8x8_cad_SendCmd(u8x8, 0x081 );u8x8_cad_SendArg(u8x8, arg_int ); /* uc1617 has range from 0 to 255 */u8x8_cad_EndTransfer(u8x8);break;
#endifdefault:return 0;}return 1;
}