一、项目框图
如下是系统简易框图。
本次用到的外设模块:RED LED, GREEN LED, BUTTON SW3, I3C p3t1755, TouchPad "E1"
2. 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来控制。
3 按键
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 *************************************************************/
4 温度传感器
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 *************************************************************/
5 触摸板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[i]);
}
/********** 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[i] , "led")==0)
{
//printf("\r\n inside httpd_cgi_ssi.c line 148. led received.");
/* Switch LED1 ON if 1 */
if(strcmp(pcValue[i], "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[i], "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[i], "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[i], "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;
}
项目效果: