在DIY小制作的时候,串口打印是查看调试信息的好方式,还可以增加一块具有I2C接口的小屏幕在板子上,展示一些数据或者打印一些调试信息,也是不错的选择。
本次体验了
- 在NXP官方IDE MCUXPRESSO中使用内置的CONFIGTOOL来配置I2C的时钟、外设参数,然后自动生成初始化代码;
- 利用上次体验的LPTMR0设计简易延迟函数
- 增加OLED驱动代码并适配MCAX156的I2C传输方式
- 成功点亮屏幕,并设计了简易计时器
一、OLED屏幕介绍
引脚介绍:
1. GND 电源地
2. VCC 电源正(3~5.5V)
3. SCL OLED 的D0 脚,在IIC 通信中为时钟管脚
4. SDA OLED 的D1 脚,在IIC 通信中为数据管脚
二、MCU CONFIG TOOL配置I2C
本次实验使用的I2C是LPI2C3,开发板已经引出SCL到Mikro BUS接口的P3_27和SDA到Mikro BUS接口的P3_28
配置LPI2C3时钟:
然后配置外设引脚:
配置LPI2C3外设参数:
注意:
- 上述Follower Address: 0x3C是OLED屏幕的7-bit地址,并且没有Sub-address。
- BufferSize设置为2是对应OLED写数据是0x40 + uint8_t,写指令是0x00 + uint8_t。这两种情况都是2个byte
三、生成I2C初始化代码
点击update code
,自动生成初始化代码:
/***********************************************************************************************************************
* LPI2C3 initialization code
**********************************************************************************************************************/
/* clang-format off */
/* TEXT BELOW IS USED AS SETTING FOR TOOLS *************************************
instance:
- name: 'LPI2C3'
- type: 'lpi2c'
- mode: 'master'
- custom_name_enabled: 'false'
- type_id: 'lpi2c_2.2.0'
- functional_group: 'BOARD_InitPeripherals'
- peripheral: 'LPI2C3'
- config_sets:
- main:
- clockSource: 'Lpi2cClock'
- clockSourceFreq: 'ClocksTool_DefaultInit'
- interrupt_vector: []
- master:
- mode: 'transfer'
- config:
- enableMaster: 'true'
- enableDoze: 'true'
- debugEnable: 'false'
- ignoreAck: 'false'
- pinConfig: 'kLPI2C_2PinOpenDrain'
- baudRate_Hz: '100000'
- busIdleTimeout_ns: '0'
- pinLowTimeout_ns: '0'
- sdaGlitchFilterWidth_ns: '0'
- sclGlitchFilterWidth_ns: '0'
- hostRequest:
- enable: 'false'
- source: 'kLPI2C_HostRequestExternalPin'
- polarity: 'kLPI2C_HostRequestPinActiveHigh'
- edmaRequestSources: ''
- transfer:
- blocking: 'false'
- enable_custom_handle: 'false'
- callback:
- name: ''
- userData: ''
- flags: ''
- slaveAddress: '0x3C'
- direction: 'kLPI2C_Write'
- subaddress: '0'
- subaddressSize: '0'
- blocking_buffer: 'false'
- enable_custom_buffer: 'false'
- dataSize: '2'
* BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR TOOLS **********/
/* clang-format on */
const lpi2c_master_config_t LPI2C3_masterConfig = {
.enableMaster = true,
.enableDoze = true,
.debugEnable = false,
.ignoreAck = false,
.pinConfig = kLPI2C_2PinOpenDrain,
.baudRate_Hz = 100000UL,
.busIdleTimeout_ns = 0UL,
.pinLowTimeout_ns = 0UL,
.sdaGlitchFilterWidth_ns = 0U,
.sclGlitchFilterWidth_ns = 0U,
.hostRequest = {
.enable = false,
.source = kLPI2C_HostRequestExternalPin,
.polarity = kLPI2C_HostRequestPinActiveHigh
}
};
lpi2c_master_transfer_t LPI2C3_masterTransfer = {
.flags = kLPI2C_TransferDefaultFlag,
.slaveAddress = 0x3C,
.direction = kLPI2C_Write,
.subaddress = 0,
.subaddressSize = 0,
.data = LPI2C3_masterBuffer,
.dataSize = 2
};
lpi2c_master_handle_t LPI2C3_masterHandle;
uint8_t LPI2C3_masterBuffer[LPI2C3_MASTER_BUFFER_SIZE];
static void LPI2C3_init(void) {
LPI2C_MasterInit(LPI2C3_PERIPHERAL, &LPI2C3_masterConfig, LPI2C3_CLOCK_FREQ);
LPI2C_MasterTransferCreateHandle(LPI2C3_PERIPHERAL, &LPI2C3_masterHandle, NULL, NULL);
}
四、适配OLED驱动
OLED在初始化的时候用到了延迟,利用上次体验的LPTMR0来制作N毫秒的延迟:
void HAL_Delay(uint32_t N_ms){
static uint32_t i;
i = cnt;
while((cnt - i) < N_ms){
;
}
}
cnt在LPTMR0_ISR中1ms更新一次数值:
void LPTMR0_IRQHANDLER(void) {
uint32_t intStatus;
/* Reading all interrupt flags of status register */
intStatus = LPTMR_GetStatusFlags(LPTMR0_PERIPHERAL);
LPTMR_ClearStatusFlags(LPTMR0_PERIPHERAL, intStatus);
/* Place your code here */
cnt++;
if(cnt%1000 == 0){
/* Toggle pin connected to LED */
GPIO_PortToggle(GPIO3, 1u << 0);
PRINTF("\r\n GPIO3_0 RED LED TOOGLED, testVal = %d", testVal++);
}
/* Add for ARM errata 838869, affects Cortex-M4, Cortex-M4F
Store immediate overlapping exception return operation might vector to incorrect interrupt. */
#if defined __CORTEX_M && (__CORTEX_M == 4U)
__DSB();
#endif
}
这样就快速实现了N毫秒延迟。
接下来就是怎么把指令或者数据通过LPI2C3总线发送出去:
/***************************************************
I2C总线传出数据函数:
addr : 要写入的地址(OLED的地址一般为0x40;指令地址为0x00)
data : 要写入的数据
***************************************************/
extern lpi2c_master_transfer_t LPI2C3_masterTransfer;
extern uint8_t LPI2C3_masterBuffer[LPI2C3_MASTER_BUFFER_SIZE];
void NXP_I2C_WriteByte(uint8_t addr,uint8_t data)
{
LPI2C3_masterBuffer[0] = addr;
LPI2C3_masterBuffer[1] = data;
LPI2C_MasterTransferBlocking(LPI2C3_PERIPHERAL, &LPI2C3_masterTransfer);
}
五、添加应用代码
主函数代码:
/*
* @brief Application entry point.
*/
int main(void) {
/* Init board hardware. */
BOARD_InitBootPins();
BOARD_InitBootClocks();
BOARD_InitBootPeripherals();
//SysTick_Config(CLOCK_GetSystickClkFreq());
/* Init FSL debug console. */
BOARD_InitDebugConsole();
PRINTF("Hello World\r\n");
PRINTF("CLOCK_GetCoreSysClkFreq = %8d\r\n", CLOCK_GetCoreSysClkFreq());
PRINTF("CLOCK_GetMainClk = %8d\r\n", CLOCK_GetMainClk());
PRINTF("CLOCK_GetSystickClkFreq = %8d\r\n", CLOCK_GetSystickClkFreq());
OLED_Init();
OLED_Refresh();
OLED_Clear();
OLED_ShowString(0, 2, "NXP 2025-01-10", 8, 1);
OLED_DrawLine(0,13, 127,13,1);
OLED_ShowString(44, 16, "10:00", 16, 1);
OLED_ShowString(86, 24, "00", 8, 1);
OLED_DrawLine(0,33, 127,33,1);
OLED_ShowString(0, 36, "Drive by HwIIC", 8, 1);
OLED_ShowString(0, 46, "Dev Addr: 0x3C", 8, 1);
OLED_ShowString(0, 55, "Good Day", 8, 1);
//OLED_ShowString(0, 12, "WB09KE", 8, 1);
OLED_Refresh();
/* Force the counter to be placed into memory. */
/* Enter an infinite loop, just incrementing a counter. */
while(1) {
sprintf(testValString, "%2dh:%2dmin:%2ds", testVal/3600, (testVal%3600)/60, (testVal%3600)%60);
OLED_ShowString(24, 16, testValString,12,0);
OLED_Refresh();
}
return 0 ;
}