我正在使用 xMega32a4u 在 Atmel Studio 6 中开发应用程序。我正在使用 Atmel 提供的 TWI 库。大部分情况下一切都很顺利。
这是我的问题:为了更新我正在使用的 OLED 显示器(SSD1306 控制器,128x32),必须在 I2C START 命令、从地址和控制字节之后立即写入显示 RAM 的全部内容,以便显示器知道将数据输入显示 RAM。如果控制字节没有紧接在显示 RAM 包之前,则没有任何作用。
我正在使用 Saleae 逻辑分析仪来验证总线是否在做它应该做的事情。
这是我用来编写显示的函数:
void OLED_buffer(){ // Used to write contents of display buffer to OLED
uint8_t data_array[513];
data_array[0] = SSD1306_DATA_BYTE;
for (int i=0;i<512;++i){
data_array[i+1] = buffer[i];
}
OLED_command(SSD1306_SETLOWCOLUMN | 0x00);
OLED_command(SSD1306_SETHIGHCOLUMN | 0x00);
OLED_command(SSD1306_SETSTARTLINE | 0x00);
twi_package_t buffer_send = {
.chip = OLED_BUS_ADDRESS,
.buffer = data_array,
.length = 513
};
twi_master_write(&TWIC, &buffer_send);
}
显然,这是非常低效的,因为每次调用此函数都会将整个数组“缓冲区”重新创建到一个新数组“data_array”中,一次一个元素。这样做的重点是将控制字节(SSD1306_DATA_BYTE = 0x40)插入到数组中,以便一次发送整个“包”,并且控制字节在正确的位置。我可以使原始的“缓冲区”数组变大一个元素并将控制字节添加为第一个元素,以跳过此过程,但这会使大小变为 513 而不是 512,并且可能会与一些操作它的文本/图形函数混淆数组并取决于它是正确的大小。
现在,我想我可以这样写代码:
void OLED_buffer(){ // Used to write contents of display buffer to OLED
uint8_t data_byte = SSD1306_DATA_BYTE;
OLED_command(SSD1306_SETLOWCOLUMN | 0x00);
OLED_command(SSD1306_SETHIGHCOLUMN | 0x00);
OLED_command(SSD1306_SETSTARTLINE | 0x00);
twi_package_t data_control_byte = {
.chip = OLED_BUS_ADDRESS,
.buffer = data_byte,
.length = 1
};
twi_master_write(&TWIC, &data_control_byte);
twi_package_t buffer_send = {
.chip = OLED_BUS_ADDRESS,
.buffer = buffer,
.length = 512
};
twi_master_write(&TWIC, &buffer_send);
}
/*
那是行不通的。第一个“twi_master_write”命令发送 START、地址、控制、STOP。然后下一个这样的命令发送一个 START、地址、数据缓冲区、STOP。因为后一个事务中缺少控制字节,所以这不起作用。当通过 I2C 总线发送时,我需要在地址字节和缓冲区数组之间插入一个 0x40 字节。twi_master_write 是 Atmel TWI 库中提供的函数。我试图检查这些库以找出它的内部工作原理,但我无法理解它。
当然,与其弄清楚如何重新创建一个 twi_write 函数以按照我需要的方式工作,还有一种更简单的方法来添加这个前面的控制字节?理想情况下,它不像我的第一个代码示例那样浪费时钟周期?实际上,显示器的更新速度仍然非常快,足以满足我的需求,但这并不能改变这是低效代码的事实。
我很感激你们可能有的任何建议。提前致谢!