项目介绍
这里是我参加Funpack第三季第四期活动的任务总结报告,我所完成的是任务二,使用板卡上的以太网接口连接到电脑上并通过以太网和电脑通信,实现数据传输。
大体上经过以下步骤:
- 开发工具与配置
本次板卡的开发将使用官方提供的IDE工具,首先通过MCUpress配置工具中的引脚配置工具,对相应的触摸按键、实体按键、温度传感器、LED以及网口引脚进行配置。 - 驱动程序移植
大部分外设的驱动程序已有现成的例程可供参考,我们只需移植相关部分即可。 - TCP连接通讯功能
我们将在此基础上添加TCP连接通讯功能。通讯部分包括数据发送与接收: - 发送:当两种按键被触发时,系统会通过以太网向PC端发送相应的数据;定时发送板载温度传感器的数据及手势传感器的接近数据。
- 接收:系统能够接收来自PC端控制LED灯亮灭状态的数据,从而实现对板上LED灯的控制。
通过以上步骤的实施,我们可以有效地实现板卡的功能并确保其与PC端的顺畅通讯。
主要硬件介绍
- MCXN947 微控制器单元 (MCU):基于双高性能 Arm Cortex-M33 核心,最高运行频率可达 150 MHz。
- 包含 2 MB 的闪存、可配置的全 ECC RAM、DSP 协处理器以及集成的专有神经处理单元 (NPU)。
- 电源供应:5V 输入电源,可通过 USB Type-C 接口、5V 调节器或 Arduino Shield 兼容头提供。
- 时钟:提供 24 MHz 系统参考时钟、32.768 kHz 实时时钟 (RTC) 和 50 MHz 以太网 PHY 时钟输入。
- USB 接口:高速 (HS) USB 模块,通过 USB Type-C 连接器提供。
- 闪存:支持 64 Mbit QSPI 闪存 (Winbond W25Q64JVSSIQ) 或 512 Mbit Octal 闪存 (Micron MT35XL512ABA1G12)。
- 温度传感器:支持 NXP P3T1755DP I3C 温度传感器。
- 以太网:10/100 Mbit/s (RMII) 局域网通过 LAN8741 以太网 PHY 和 RJ45 连接器提供。
- I/O 头:兼容 Arduino shields、MikroBUS、相机模块、LCD 模块和 Pmod 板。
- CAN 接口:通过 TJA1057GTK/3Z CAN PHY 和 4 针 CAN FD 连接器提供。
- 触摸板:提供触摸感应输入。
- 调试接口:板载 MCU-Link 调试探针,支持 CMSIS-DAP 和 SEGGER J-Link 协议选项。
- 状态指示 LED:包括 RGB LED 和其他用于指示电源状态和复位状态的 LED。
- 连接器和跳线:提供多种类型的连接器和跳线,用于不同的功能和配置选项。
- 其他:支持 microSDHC 卡槽 (默认不安装),以及用于连接相机模块和 NXP 低成本 LCD 模块的接口。
这些资源为开发者提供了广泛的硬件支持,适用于各种开发和评估任务。如嵌入式系统开发,机器学习和人工智能,传感器数据采集。
主要软件介绍
在软件开发上,官方提供了丰富的例程,我们可以通过移植或模仿例程中的代码,从而驱动我们所要使用的外设
我选择在该例程的基础上进行移植工作
先对板子的引脚进行配置,在项目程序上右键,打开引脚
在下方的路由详情那,点击加好添加自己所要用到的引脚
接下来就是添加自己的业务代码了
添加了几个文件,第一个箭头是板子上的温度传感器驱动程序,从官方例程中移植来,第二个是软件I2C的程序,用于驱动手势传感器,第三个箭头则是创建一个tcp服务器,从网上的lwip讲解中移植而来。
void other1_init(){
/* Define the init structure for the input switch pin */
gpio_pin_config_t sw_config = {
kGPIO_DigitalInput,
0,
};
/* Define the init structure for the output LED pin */
gpio_pin_config_t led_config = {
kGPIO_DigitalOutput,
1,
};
CLOCK_EnableClock(kCLOCK_Gpio0);
GPIO_SetPinInterruptConfig(BOARD_SW_GPIO, BOARD_SW_GPIO_PIN, kGPIO_InterruptFallingEdge);
EnableIRQ(BOARD_SW_IRQ);
GPIO_PinInit(BOARD_SW_GPIO, BOARD_SW_GPIO_PIN, &sw_config);
/* Init output LED GPIO. */
GPIO_PinInit(BOARD_LED_GPIO, BOARD_LED_GPIO_PIN, &led_config);
PRINTF("other1_init\r\n");
}
这个是板子上的实体按键及led驱动初始化程序,其中按键引脚绑定了中断函数,在按键按下时,会触发中断并设置标志位,并主循环中进行处理相关业务
void other2_init(){
volatile uint32_t i = 0;
tsi_selfCap_config_t tsiConfig_selfCap;
lptmr_config_t lptmrConfig;
memset((void *)&lptmrConfig, 0, sizeof(lptmrConfig));
/* Enables the clk_16k[1] */
CLOCK_SetupClk16KClocking(kCLOCK_Clk16KToVsys);
/* attach FRO HF to SCT */
CLOCK_SetClkDiv(kCLOCK_DivTsiClk, 1u);
CLOCK_AttachClk(kCLK_IN_to_TSI);
/* Configure LPTMR */
LPTMR_GetDefaultConfig(&lptmrConfig);
/* TSI default hardware configuration for self-cap mode */
TSI_GetSelfCapModeDefaultConfig(&tsiConfig_selfCap);
/* Initialize the LPTMR */
LPTMR_Init(LPTMR0, &lptmrConfig);
/* Initialize the TSI */
TSI_InitSelfCapMode(APP_TSI, &tsiConfig_selfCap);
/* Enable noise cancellation function */
TSI_EnableNoiseCancellation(APP_TSI, true);
/* Set timer period */
LPTMR_SetTimerPeriod(LPTMR0, USEC_TO_COUNT(LPTMR_USEC_COUNT, LPTMR_SOURCE_CLOCK));
NVIC_EnableIRQ(TSI0_IRQn);
TSI_EnableModule(APP_TSI, true); /* Enable module */
PRINTF("\r\nTSI_V6 Self-Cap mode Example Start!\r\n");
/********* CALIBRATION PROCESS ************/
memset((void *)&buffer, 0, sizeof(buffer));
TSI_SelfCapCalibrate(APP_TSI, &buffer);
/* Print calibrated counter values */
for (i = 0U; i < FSL_FEATURE_TSI_CHANNEL_COUNT; i++)
{
PRINTF("Calibrated counters for channel %d is: %d \r\n", i, buffer.calibratedData[i]);
}
/********** HARDWARE TRIGGER SCAN ********/
PRINTF("\r\nNOW, comes to the hardware trigger scan method!\r\n");
TSI_EnableModule(APP_TSI, false);
TSI_EnableHardwareTriggerScan(APP_TSI, true);
TSI_EnableInterrupts(APP_TSI, kTSI_EndOfScanInterruptEnable);
TSI_ClearStatusFlags(APP_TSI, kTSI_EndOfScanFlag);
TSI_SetSelfCapMeasuredChannel(APP_TSI,
BOARD_TSI_ELECTRODE_1); /* Select BOARD_TSI_ELECTRODE_1 as detecting electrode. */
TSI_EnableModule(APP_TSI, true);
INPUTMUX_AttachSignal(INPUTMUX0, 0U, kINPUTMUX_Lptmr0ToTsiTrigger);
LPTMR_StartTimer(LPTMR0); /* Start LPTMR triggering */
}
这个则是板子的触摸按键的初始化部分,NXP FRDM-MCXN947 开发板上的触摸按键通过触摸感应输入(Touch sensing input, TSI)实现。具体来说,开发板上有一个触摸滑块(Touch Slider),它连接到目标微控制器的 TSI 输入通道。这种设计允许我们通过触摸操作来实现按钮功能,如滑动或按下动作。
- 触摸感应输入(TSI):微控制器内置的 TSI 模块能够检测触摸滑块上的触摸事件。TSI 通过一组电极检测触摸,并将其转换为电信号。
- 触摸滑块:开发板上的触摸滑块是用户直接接触的部分,用户可以通过滑动或触摸来触发不同的功能。
- 信号处理:TSI 模块会处理触摸滑块上的信号,并将其转换为微控制器可以识别的数字信号。
- 软件配置:需要在微控制器的固件中配置 TSI 功能,包括设置电极数量、灵敏度、中断触发条件等。
- 用户交互:开发板上的触摸按键可以用于实现各种用户交互功能,如调节音量、切换菜单、控制设备等。
- 去抖动:触摸按键通常会配备去抖动电路,以确保触摸信号的稳定性和准确性。去抖动电路可以是硬件实现,也可以通过软件算法实现。
通过这种设计,NXP FRDM-MCXN947 开发板能够提供一种无需物理按键的交互方式,使得用户界面更加直观和现代。
void other3_init(){
status_t result = kStatus_Success;
i3c_master_config_t masterConfig;
p3t1755_config_t p3t1755Config;
/* Attach PLL0 clock to I3C, 150MHz / 6 = 25MHz. */
CLOCK_SetClkDiv(kCLOCK_DivI3c1FClk, 6U);
CLOCK_AttachClk(kPLL0_to_I3C1FCLK);
PRINTF("\r\nI3C master read sensor data example.\r\n");
I3C_MasterGetDefaultConfig(&masterConfig);
masterConfig.baudRate_Hz.i2cBaud = EXAMPLE_I2C_BAUDRATE;
masterConfig.baudRate_Hz.i3cPushPullBaud = EXAMPLE_I3C_PP_BAUDRATE;
masterConfig.baudRate_Hz.i3cOpenDrainBaud = EXAMPLE_I3C_OD_BAUDRATE;
masterConfig.enableOpenDrainStop = false;
masterConfig.disableTimeout = true;
I3C_MasterInit(EXAMPLE_MASTER, &masterConfig, I3C_MASTER_CLOCK_FREQUENCY);
/* Create I3C handle. */
I3C_MasterTransferCreateHandle(EXAMPLE_MASTER, &g_i3c_m_handle, &masterCallback, NULL);
result = p3t1755_set_dynamic_address();
if (result != kStatus_Success)
{
PRINTF("\r\nP3T1755 set dynamic address failed.\r\n");
}
p3t1755Config.writeTransfer = I3C_WriteSensor;
p3t1755Config.readTransfer = I3C_ReadSensor;
p3t1755Config.sensorAddress = SENSOR_ADDR;
P3T1755_Init(&p3t1755Handle, &p3t1755Config);
}
这是板子的p3t1755温度传感器的初始化部分,这个传感器支持 I3C 通信协议,允许通过 I3C 接口与微控制器进行通信,以获取温度数据。I3C 接口是一种用于嵌入式系统和传感器的串行通信接口,它支持多主设备和多从设备,以及更高的数据传输速率,从而简化了系统设计并提高了效率。
void tcp_pyqt5_send(uint8_t *buf,uint8_t buf_len){
if(pcb_1 != NULL)
tcp_write(pcb_1, buf, buf_len, 1);
}
static err_t tcpecho_recv(void *arg,
struct tcp_pcb *tpcb,
struct pbuf *p,
err_t err)
{
if (p != NULL)
{
/* 更新窗口*/
tcp_recved(tpcb, p->tot_len);
strncpy(recv_str,p->payload,p->len);
recv_str[p->len]= '\0';
/* 返回接收到的数据*/
// tcp_write(tpcb, p->payload, p->tot_len, 1);
PRINTF("recv: %s\r\n",recv_str);
GPIO_PortToggle(BOARD_LED_RED_GPIO, 1U << BOARD_LED_RED_GPIO_PIN);
memset(p->payload, 0 , p->tot_len);
pbuf_free(p);
}
else if (err == ERR_OK)
{
return tcp_close(tpcb);
}
return ERR_OK;
}
static err_t tcpecho_accept(void *arg,
struct tcp_pcb *newpcb,
err_t err)
{
tcp_recv(newpcb, tcpecho_recv);
pcb_1=newpcb;
PRINTF("accept success\r\n");
return ERR_OK;
}
void TCP_Echo_Init(void)
{
struct tcp_pcb *pcb = NULL;
/* 创建一个TCP控制块 */
pcb = tcp_new();
/* 绑定TCP控制块 */
tcp_bind(pcb, IP_ADDR_ANY, TCP_ECHO_PORT);
/* 进入监听状态 */
pcb = tcp_listen(pcb);
/* 处理连接 */
tcp_accept(pcb, tcpecho_accept);
}
这是tcp服务器部分,构建了一个简单的 TCP 回显服务器,能够接受来自客户端的连接,接收数据并打印,同时可以向客户端发送数据。LED 的状态变化用于指示有数据接收事件发生。这一过程涉及对 TCP 协议相关操作的管理,包括连接、数据接收与发送等。
while (1)
{
/* Poll the driver, get any outstanding frames */
ethernetif_input(&netif);
sys_check_timeouts(); /* Handle all system timeouts for all core protocols */
if (g_ButtonPress)
{
PRINTF(" %s is pressed \r\n", BOARD_SW_NAME);
/* Toggle LED. */
// GPIO_PortToggle(BOARD_LED_GPIO, 1U << BOARD_LED_GPIO_PIN);
/* Reset state of button. */
send_data(0xbb,1,0);
g_ButtonPress = false;
}
if(!s_tsiInProgress){
PRINTF("touched\r\n");
send_data(0xcc,1,0);
s_tsiInProgress=true;
}
temperature_data_send();
SDK_DelayAtLeastUs(200*1000, CLOCK_GetCoreSysClkFreq());
readProximity(&proximity_data);
// PRINTF("::%d\r\n",proximity_data);
send_data(0xdd,proximity_data,0);
SDK_DelayAtLeastUs(300*1000, CLOCK_GetCoreSysClkFreq());
}
这是主任务循环中,不断检测是否触发了事件,并对事件进行相应的处理,同时发送温度及手势传感器的接近值数据
效果展示
上位机的界面
显示相应的数据
总结
在本次活动中,学习了如何使用pyqt5进行上位机的制作。在过程中遇到的问题,通过百度搜索都能找到适合的答案,使自我得到了提升,感谢硬禾学堂平台。