本帖最后由 SensorYoung 于 2024-12-3 20:28 编辑
响应论坛年终庆典活动,特此分享小弟前段时间做的MCXN947以太网采集传感器数据并在网页进行展示。
板卡介绍: FRDM-MCXN947是一款紧凑且可扩展的开发板,可让您快速基于MCX N94x MCU开展原型设计。板卡上集成行业标准的接口,可轻松使用MCU的I/O、集成的开放标准串行接口、外部闪存和板载MCU-Link调试器。
本次用到的外设模块:RED LED, GREEN LED, BUTTON SW3, I3C p3t1755, TouchPad "E1"
项目框图 如下是系统简易框图。 板卡实物照片:
传感器等外设驱动 LED: FRDM-MCXN947开发板有个RGB的三色小灯,电路原理图如下: 初始化代码的引脚配置部分如下: - const port_pin_config_t port0_10_pinB12_config = {/* Internal pull-up/down resistor is disabled */
- kPORT_PullDisable,
- /* Low internal pull resistor value is selected. */
- kPORT_LowPullResistor,
- /* Fast slew rate is configured */
- kPORT_FastSlewRate,
- /* Passive input filter is disabled */
- kPORT_PassiveFilterDisable,
- /* Open drain output is disabled */
- kPORT_OpenDrainDisable,
- /* Low drive strength is configured */
- kPORT_LowDriveStrength,
- /* Pin is configured as PIO0_10 */
- kPORT_MuxAlt0,
- /* Digital input enabled */
- kPORT_InputBufferEnable,
- /* Digital input is not inverted */
- kPORT_InputNormal,
- /* Pin Control Register fields [15:0] are not locked */
- kPORT_UnlockRegister};
- /* PORT0_10 (pin B12) is configured as PIO0_10 */
- PORT_SetPinConfig(PORT0, 10U, &port0_10_pinB12_config);
- const port_pin_config_t port0_27_pinE10_config = {/* Internal pull-up/down resistor is disabled */
- kPORT_PullDisable,
- /* Low internal pull resistor value is selected. */
- kPORT_LowPullResistor,
- /* Fast slew rate is configured */
- kPORT_FastSlewRate,
- /* Passive input filter is disabled */
- kPORT_PassiveFilterDisable,
- /* Open drain output is disabled */
- kPORT_OpenDrainDisable,
- /* Low drive strength is configured */
- kPORT_LowDriveStrength,
- /* Pin is configured as PIO0_10 */
- kPORT_MuxAlt0,
- /* Digital input enabled */
- kPORT_InputBufferEnable,
- /* Digital input is not inverted */
- kPORT_InputNormal,
- /* Pin Control Register fields [15:0] are not locked */
- kPORT_UnlockRegister};
- /* PORT0_27 (pin E10) is configured as PIO0_27 */
- PORT_SetPinConfig(PORT0, 27U, &port0_27_pinE10_config);
-
- const port_pin_config_t port1_2_pinC4_config = {/* Internal pull-up/down resistor is disabled */
- kPORT_PullDisable,
- /* Low internal pull resistor value is selected. */
- kPORT_LowPullResistor,
- /* Fast slew rate is configured */
- kPORT_FastSlewRate,
- /* Passive input filter is disabled */
- kPORT_PassiveFilterDisable,
- /* Open drain output is disabled */
- kPORT_OpenDrainDisable,
- /* Low drive strength is configured */
- kPORT_LowDriveStrength,
- /* Pin is configured as PIO1_2 */
- kPORT_MuxAlt0,
- /* Digital input enabled */
- kPORT_InputBufferEnable,
- /* Digital input is not inverted */
- kPORT_InputNormal,
- /* Pin Control Register fields [15:0] are not locked */
- kPORT_UnlockRegister};
- /* PORT1_2 (pin C4) is configured as PIO1_2 */
- PORT_SetPinConfig(PORT1, 2U, &port1_2_pinC4_config);
复制代码
之后调用初始化函数: - LED_RED_INIT(LOGIC_LED_OFF);
- LED_GREEN_INIT(LOGIC_LED_OFF);
- LED_BLUE_INIT(LOGIC_LED_OFF);
复制代码
至此,LED部分的驱动完成。在后面的设计中,红色和绿色小灯将由网页直接控制,蓝色小灯会有触摸板E1来控制。
按键 FRDM开发板的SW3可以用作ISP功能,也可以当作普通的按键。 配置引脚: - const port_pin_config_t port0_6_pinC14_config = {/* Internal pull-up resistor is enabled */
- kPORT_PullUp,
- /* Low internal pull resistor value is selected. */
- kPORT_LowPullResistor,
- /* Fast slew rate is configured */
- kPORT_FastSlewRate,
- /* Passive input filter is disabled */
- kPORT_PassiveFilterDisable,
- /* Open drain output is disabled */
- kPORT_OpenDrainDisable,
- /* Low drive strength is configured */
- kPORT_LowDriveStrength,
- /* Pin is configured as PIO0_6 */
- kPORT_MuxAlt0,
- /* Digital input enabled */
- kPORT_InputBufferEnable,
- /* Digital input is not inverted */
- kPORT_InputNormal,
- /* Pin Control Register fields [15:0] are not locked */
- kPORT_UnlockRegister};
- /* PORT0_6 (pin C14) is configured as PIO0_6 */
- PORT_SetPinConfig(PORT0, 6U, &port0_6_pinC14_config);
- 接下来类似LED,进行初始化SW3:
- /********************* SW3 INIT BEGIN *************************************************************/
-
- /* Define the init structure for the input switch pin */
- gpio_pin_config_t sw_config = {
- kGPIO_DigitalInput,
- 0,
- };
-
- GPIO_PinInit(BOARD_SW_GPIO, BOARD_SW_GPIO_PIN, &sw_config);
- /********************* SW3 INIT DONE *************************************************************/
复制代码
温度传感器 FRDM-MCXN947开发板上有一颗i3c接口的温度传感器。这个i3c是i2c的升级版。 I3C,全称为Improved Inter-Integrated Circuit,是一种由MIPI联盟发布的通信总线接口标准。作为I2C(Inter-Integrated Circuit)的升级版,I3C不仅继承了I2C的2线传输特性,还在性能、功耗和扩展性方面进行了显著的改进。 初始化代码: - /********************* i3c INIT BEGIN *************************************************************/
-
- 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);
-
- char tempVal[15]={'\0'};
- /********************* i3c INIT END *************************************************************/
复制代码
触摸板E1 FRDM开发板上的E1是一个触摸板,原理图如下:
TSI模块初始化: - /********************* tsi touch pad INIT BEGIN *************************************************************/
- /* 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);
- }
- /********** HARDWARE TRIGGER SCAN ********/
- PRINTF("\r\nNOW, comes to the hardware trigger scan method!\r\n");
- PRINTF("After running, touch pad %s each time, you will see LED toggles.\r\n", PAD_TSI_ELECTRODE_1_NAME);
- 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 */
复制代码
其中,TSI模块开启硬件中断: - void TSI0_IRQHandler(void)
- {
- if (TSI_GetSelfCapMeasuredChannel(APP_TSI) == BOARD_TSI_ELECTRODE_1)
- {
- if (TSI_GetCounter(APP_TSI) > (uint16_t)(buffer.calibratedData[BOARD_TSI_ELECTRODE_1] + TOUCH_DELTA_VALUE))
- {
- LED1_TOGGLE(); /* Toggle the touch event indicating LED */
- s_tsiInProgress = true;
- }
- }
- /* Clear endOfScan flag */
- TSI_ClearStatusFlags(APP_TSI, kTSI_EndOfScanFlag);
- SDK_ISR_EXIT_BARRIER;
- }
复制代码
至此,TSI模块初始化完毕。
增加LwIp HTTPD服务器: FRDM-MCXN947开发板的固件库提供了Lwip httpsrv这个例程,里面有个简单的http服务器,本文拿来参考其中的初始化代码: - CLOCK_AttachClk(MUX_A(CM_ENETRMIICLKSEL, 0));
- CLOCK_EnableClock(kCLOCK_Enet);
- SYSCON0->PRESETCTRL2 = SYSCON_PRESETCTRL2_ENET_RST_MASK;
- SYSCON0->PRESETCTRL2 &= ~SYSCON_PRESETCTRL2_ENET_RST_MASK;
- MDIO_Init();
- g_phy_resource.read = MDIO_Read;
- g_phy_resource.write = MDIO_Write;
- time_init();
- /* Set MAC address. */
- #ifndef configMAC_ADDR
- (void)SILICONID_ConvertToMacAddr(&enet_config.macAddress);
- #endif
- /* Get clock after hardware init. */
- enet_config.srcClockHz = EXAMPLE_CLOCK_FREQ;
- #if LWIP_IPV4
- IP4_ADDR(&netif_ipaddr, configIP_ADDR0, configIP_ADDR1, configIP_ADDR2, configIP_ADDR3);
- IP4_ADDR(&netif_netmask, configNET_MASK0, configNET_MASK1, configNET_MASK2, configNET_MASK3);
- IP4_ADDR(&netif_gw, configGW_ADDR0, configGW_ADDR1, configGW_ADDR2, configGW_ADDR3);
- #endif /* LWIP_IPV4 */
- lwip_init();
- #if LWIP_IPV4
- netif_add(&netif, &netif_ipaddr, &netif_netmask, &netif_gw, &enet_config, EXAMPLE_NETIF_INIT_FN, ethernet_input);
- #else
- netif_add(&netif, &enet_config, EXAMPLE_NETIF_INIT_FN, ethernet_input);
- #endif /* LWIP_IPV4 */
- netif_set_default(&netif);
- netif_set_up(&netif);
- #if LWIP_IPV6
- netif_create_ip6_linklocal_address(&netif, 1);
- #endif /* LWIP_IPV6 */
- while (ethernetif_wait_linkup(&netif, 5000) != ERR_OK)
- {
- PRINTF("PHY Auto-negotiation failed. Please check the cable connection and link partner setting.\r\n");
- }
- //httpd_init();
- http_server_init();
- #if LWIP_IPV6
- set_ipv6_valid_state_cb(netif_ipv6_callback);
- #endif /* LWIP_IPV6 */
- PRINTF("\r\n***********************************************************\r\n");
- PRINTF(" HTTP Server example\r\n");
- PRINTF("***********************************************************\r\n");
- #if LWIP_IPV4
- PRINTF(" IPv4 Address : %u.%u.%u.%u\r\n", ((u8_t *)&netif_ipaddr)[0], ((u8_t *)&netif_ipaddr)[1],
- ((u8_t *)&netif_ipaddr)[2], ((u8_t *)&netif_ipaddr)[3]);
- PRINTF(" IPv4 Subnet mask : %u.%u.%u.%u\r\n", ((u8_t *)&netif_netmask)[0], ((u8_t *)&netif_netmask)[1],
- ((u8_t *)&netif_netmask)[2], ((u8_t *)&netif_netmask)[3]);
- PRINTF(" IPv4 Gateway : %u.%u.%u.%u\r\n", ((u8_t *)&netif_gw)[0], ((u8_t *)&netif_gw)[1],
- ((u8_t *)&netif_gw)[2], ((u8_t *)&netif_gw)[3]);
- #endif /* LWIP_IPV4 */
- #if LWIP_IPV6
- print_ipv6_addresses(&netif);
- #endif /* LWIP_IPV6 */
- PRINTF("***********************************************************\r\n");
- while (1)
- {
-
- /* Poll the driver, get any outstanding frames */
- ethernetif_input(&netif);
- sys_check_timeouts(); /* Handle all system timeouts for all core protocols */
- }
复制代码
在本设计中,使用CGI和SSI技术,来实现网页控制LED灯,以及把温度传感器数据上报到网页的目标。 其中CGI部分是嵌入在网页html代码中的,定义如下: - <form method="get" action="/leds.cgi"><input value="1" name="led" type="checkbox">RED ON<br>
- <input value="2" name="led" type="checkbox">RED OFF<br>
- <input value="3" name="led" type="checkbox">GREEN ON<br>
- <input value="4" name="led" type="checkbox">GREEN OFF
- <br>
- <br>
- <input value="Send" type="submit"> </form>
复制代码
网页预览如下: 在勾选RED ON,然后点击SEND后,MCXN947就会接受到相应的以太网报文并进行解析: - const char * LEDS_CGI_Handler(int iIndex, int iNumParams, char *pcParam[], char *pcValue[])
- {
- //printf("\r\n inside httpd_cgi_ssi.c line 132. LEDS_CGI_Handler was Called.");
- LWIP_DEBUGF(HTTPD_DEBUG, ("\r\n *************************************************************"));
- LWIP_DEBUGF(HTTPD_DEBUG, ("\r\ninside httpd_cgi_ssi.c line 132. LEDS_CGI_Handler was Called."));
-
- uint32_t i=0;
-
- /* We have only one SSI handler iIndex = 0 */
- if (iIndex==0)
- {
- /* All LEDs off */
- LED_RED_OFF();
- LED_GREEN_OFF();
-
- /* Check cgi parameter : example GET /leds.cgi?led=2&led=4 */
- for (i=0; i<iNumParams; i++)
- {
- /* check parameter "led" */
- if (strcmp(pcParam , "led")==0)
- {
- //printf("\r\n inside httpd_cgi_ssi.c line 148. led received.");
-
- /* Switch LED1 ON if 1 */
- if(strcmp(pcValue, "1") ==0) {
- LWIP_DEBUGF(HTTPD_DEBUG, ("\r\n ********>>>> LED FOUND <<<<<<**"));
- LWIP_DEBUGF(HTTPD_DEBUG, ("\r\n matched led1"));
- LWIP_DEBUGF(HTTPD_DEBUG, ("\r\n ***************************"));
- LED_RED_ON();
- }
-
-
- /* Switch LED2 ON if 2 */
- else if(strcmp(pcValue, "2") ==0){
- LWIP_DEBUGF(HTTPD_DEBUG, ("\r\n ********>>>> LED FOUND <<<<<<**"));
- LWIP_DEBUGF(HTTPD_DEBUG, ("\r\n matched led2"));
- LWIP_DEBUGF(HTTPD_DEBUG, ("\r\n ***************************"));
- LED_RED_OFF();
- }
- //BSP_LED_On(LED2);
-
- /* Switch LED3 ON if 3 */
- else if(strcmp(pcValue, "3") ==0){
- LWIP_DEBUGF(HTTPD_DEBUG, ("\r\n ********>>>> LED FOUND <<<<<<**"));
- LWIP_DEBUGF(HTTPD_DEBUG, ("\r\n matched led3"));
- LWIP_DEBUGF(HTTPD_DEBUG, ("\r\n ***************************"));
- LED_GREEN_ON();
- }
-
- /* Switch LED4 ON if 4 */
- else if(strcmp(pcValue, "4") ==0){
- LWIP_DEBUGF(HTTPD_DEBUG, ("\r\n ********>>>> LED FOUND <<<<<<**"));
- LWIP_DEBUGF(HTTPD_DEBUG, ("\r\n matched led4"));
- LWIP_DEBUGF(HTTPD_DEBUG, ("\r\n ***************************"));
- LED_GREEN_OFF();
- }//<--END OF IF -->
- }
- }//<--END OF FOOR LOOP-->
- }//<--END OF IF(INDEX == 0)-->
- /* uri to send after cgi call*/
- return "/NXPMCXN947LED.html";
- }
复制代码
SSI技术用于把触摸,按键以及温度信息上报给浏览器: 注意<!--#b-->这其中的b就是一个变量,后面可以在代码里去更新这个值,然后由于网页是定时刷新的,所以浏览器那边也可以看到最近更新的值。 利用这种方式,b代表button; t代表温度;s代表触摸传感器。 SSI部分对应的代码: - u16_t Button_Handler(int iIndex, char *pcInsert, int iInsertLen)
- {
- /* We have only 3 SSI handler, iIndex = 0 */
- static uint32_t tempCnt = 0;
- static double temperature;
-
- switch(iIndex){
- case 0:
- if((0 == GPIO_PinRead(BOARD_SW3_GPIO, BOARD_SW3_GPIO_PIN))){
- LWIP_DEBUGF(HTTPD_DEBUG, ("\r\n ********>>>> BUTTON PRESSED <<<<<<**"));
- LWIP_DEBUGF(HTTPD_DEBUG, ("\r\n SW3 (P0_6)"));
- LWIP_DEBUGF(HTTPD_DEBUG, ("\r\n ***************************"));
- /* prepare data to be inserted in html */
- *pcInsert = (char)(66);
- *(pcInsert + 1) = (char)(84);
- *(pcInsert + 2) = (char)(78);
- *(pcInsert + 3) = (char)(45);
- *(pcInsert + 4) = (char)(79);
- *(pcInsert + 5) = (char)(78);
- *(pcInsert + 6) = (char)(32);
- }else{
- /* prepare data to be inserted in html */
- *pcInsert = (char)(66);
- *(pcInsert + 1) = (char)(84);
- *(pcInsert + 2) = (char)(78);
- *(pcInsert + 3) = (char)(45);
- *(pcInsert + 4) = (char)(79);
- *(pcInsert + 5) = (char)(70);
- *(pcInsert + 6) = (char)(70);
- }
-
- /* 7 characters need to be inserted in html*/
- return 7;
- break;
-
- case 1:
- P3T1755_ReadTemperature(&p3t1755Handle, &temperature);
- sprintf(pcInsert, "%.3f", temperature);
- return strlen(pcInsert);
- break;
-
- case 2:
- if(true == s_tsiInProgress){
- sprintf(pcInsert, "%s", "Touch Detected..");
- s_tsiInProgress = false;
- }else{
- sprintf(pcInsert, "%s", "..");
- }
- return strlen(pcInsert);
- break;
-
- default:
- break;
-
- }
- return 0;
- }
复制代码
实物视频:
|