K32W061以ARM®Cortex®-M4 为内核,主频为48MHz,内含640KBEmbedded Flash,152KB SRAM ,128KB ROM 2. 1 x NOR Flash 1MB、1 x FT230XS、2 x 13pinArduino Interface 3. 2 x I2Cs、2 x SPI、2 x UARTs、10bit x PWM、1 x DMIC、1 x QSPI 、22 x GPIOs、1 x 12bit ADC、1 x 10bit DAC、1 × IR Module、1 × RNG等。
限于篇幅的原因,这里仅介绍功能相对独立的PWM、RTC、A/D及UART的使用。
1.PWM
利用PWM的占空比调节作用可以通过LED的亮度,但比较不便的是该输出口处于PIO3上,为此,要观察调节过程只能外观一个LED指示模块。
该PWM调节的主程序为:
int main(void){ pwm_config_t pwmConfig; uint32_t pwmSourceClockFreq; uint32_t pwmChannelClockFreq; SYSCON->CODESECURITYPROT = 0x87654320; BOARD_BootClockRUN(); BOARD_InitDebugConsole(); BOARD_InitPins(); /* Get default configuration */ PWM_GetDefaultConfig(&pwmConfig); /* PWM Init with default clock selected */ PWM_Init(EXAMPLE_PWM, &pwmConfig); /* Get the default source clock frequency */ pwmSourceClockFreq = CLOCK_GetFreq(kCLOCK_Pwm); /* Set up PWM channel to generate PWM pulse of 10ms with a starting 100% duty cycle */ pwmChan.pol_ctrl = kPWM_SetHighOnMatchLowOnPeriod; pwmChan.dis_out_level = kPWM_SetLow; pwmChan.prescaler_val = 0; pwmChannelClockFreq = pwmSourceClockFreq / (1 + pwmChan.prescaler_val); pwmChan.period_val = USEC_TO_COUNT(10000, pwmChannelClockFreq); /* Compare value starts same as period value to give a 100% starting duty cycle */ pwmChan.comp_val = pwmChan.period_val; PWM_SetupPwm(EXAMPLE_PWM, kPWM_Pwm3, (pwm_setup_t *)&pwmChan); /* Clear interrupt status for PWM channel */ PWM_ClearStatusFlags(EXAMPLE_PWM, kPWM_Pwm3); /* Enable IRQ in NVIC for PWM channel 3 */ EnableIRQ(PWM3_IRQn); /* Enable PWM channel interrupt */ PWM_EnableInterrupts(EXAMPLE_PWM, kPWM_Pwm3); /* Start the PWM generation channel */ PWM_StartTimer(EXAMPLE_PWM, kPWM_Pwm3); while (1) { __WFI(); } }
复制代码主程序是通过中断来周期性的修改占空比以产生调节效果,其变化梯度为1/2000,其中断程序如下:
voidPWM3_IRQHandler(void){ staticuint32_t count = 2000; count--; if (count == 0) { count = 2000; } /* Change the compare value in the channel setup structure to change the duty cycle, ramping up over 2000 steps */ pwmChan.comp_val = (count * pwmChan.period_val) / 2000; /* Re-apply the channel setup to update the compare value */ PWM_SetupPwm(EXAMPLE_PWM, kPWM_Pwm3, (pwm_setup_t *)&pwmChan); /* Handle PWM channel interrupt, clear interrupt status */ PWM_ClearStatusFlags(EXAMPLE_PWM, kPWM_Pwm3); }
复制代码 经编译和下载,其执行效果如图1所示。
![1.jpg 1.jpg](https://static.assets-stash.eet-china.com/forum/202109/17/000444mp90s5zavtszebjv.jpg)
![1b.jpg 1b.jpg](https://static.assets-stash.eet-china.com/forum/202109/17/000444s3vhca3p3c2pv46q.jpg)
图1运行效果
动画演示1:
![pwm.gif pwm.gif](https://static.assets-stash.eet-china.com/forum/202109/17/105529ypcv5vcc9ur5pp91.gif)
2.RTC电子时钟
在K32W061片内,配有RTC计时器,通过与OLED屏配合即可轻松实现一个电子时钟。
由于前面已提供了OLED屏的驱动方法及程序,因此通过下面的程序即可了解RTC的使用方法。
电子时钟的程序为:
int main(void){ uint32_t sec; uint32_t currSeconds; uint8_t index,t,d; rtc_datetime_t date; /* Board pin, clock, debug console init */ /* Security code to allow debug access */ gpio_pin_config_t led_config = {kGPIO_DigitalOutput,1,}; SYSCON->CODESECURITYPROT = 0x87654320; /* Init the boards */ BOARD_BootClockRUN(); BOARD_InitDebugConsole(); BOARD_InitPins(); /* RTC clocks dividers */ CLOCK_SetClkDiv(kCLOCK_DivRtcClk, 32, false); CLOCK_SetClkDiv(kCLOCK_DivRtc1HzClk, 1, false); CLOCK_uDelay(10000); /* Init output LED GPIO. */ GPIO_PortInit(GPIO, BOARD_LED_PORT); GPIO_PinInit(GPIO, BOARD_LED_PORT, 11, &led_config); GPIO_PinInit(GPIO, BOARD_LED_PORT, 10, &led_config); OLED_Init(); OLED_Clear(); OLED_ShowChar(16,0,'-',16); OLED_ShowChar(40,0,'-',16); OLED_ShowChar(16,2,':',16); OLED_ShowChar(40,2,':',16); /* Init RTC */ RTC_Init(RTC); /* Set a start date time and start RT */ date.year = 2021U; date.month = 9U; date.day = 15U; date.hour = 9U; date.minute = 30; date.second = 0; /* RTC time counter has to be stopped before setting the date & time in the TSR register */ RTC_StopTimer(RTC); /* Set RTC time to default */ RTC_SetDatetime(RTC, &date); /* Start the RTC time counter */ RTC_StartTimer(RTC); RTC_GetDatetime(RTC, &date); OLED_ShowNum(0,0,date.year,2,16); OLED_ShowNum(24,0,date.month,2,16); OLED_ShowNum(48,0,date.day,2,16); t=date.second; d=date.day; while (1) { RTC_GetDatetime(RTC, &date); if(t!=date.second) { if(t!=date.second) { OLED_ShowNum(0,0,date.year,2,16); OLED_ShowNum(24,0,date.month,2,16); OLED_ShowNum(48,0,date.day,2,16); } OLED_ShowNum(0,2,date.hour,2,16); OLED_ShowNum(24,2,date.minute,2,16); OLED_ShowNum(48,2,date.second,2,16); t=date.second; } } }
复制代码该程序的处理流程为:先进行初始化,然后设置系统的起始时间并启动RTC,最终通过循环体内显示处理来输出RTC计时值。值得注意的是,为了防止过度的更新处理,是在出现秒变化时才进行时间的更新,而日期的更新则是在日期变化时。
经编译和下载,其执行效果如图2所示。
![2.jpg 2.jpg](https://static.assets-stash.eet-china.com/forum/202109/17/000444nt0o444t8ohoso3y.jpg)
图2运行效果
动画演示2:(文件大小受限,无法上传)
3.A/D
使用A/D 的数模转换功能可以采集外部的模拟信号,在配合OLED屏显示的情况下,可直观地观察到检测结果。
下面是由A0口获取模拟信号的检测主程序:
intmain(void){ /* Initialize board hardware. */ /* Security code to allow debug access */ /* Board pin, clock, debug console init */ /* Security code to allow debug access */ gpio_pin_config_t led_config = {kGPIO_DigitalOutput,1,}; SYSCON->CODESECURITYPROT = 0x87654320; /* reset FLEXCOMM for USART */ RESET_PeripheralReset(kFC0_RST_SHIFT_RSTn); /* Init the boards */ BOARD_BootClockRUN(); BOARD_InitDebugConsole(); BOARD_InitPins(); /* Enable the power and clock for ADC. */ ADC_ClockPower_Configuration(); PRINTF("ADC basic example.\r\n"); #if !(defined(FSL_FEATURE_ADC_HAS_NO_CALIB_FUNC) && FSL_FEATURE_ADC_HAS_NO_CALIB_FUNC) #ifdefined(FSL_FEATURE_ADC_HAS_CALIB_REG) && FSL_FEATURE_ADC_HAS_CALIB_REG /* Calibration after power up. */ if (ADC_DoSelfCalibration(DEMO_ADC_BASE)) #else uint32_t frequency; #ifdefined(SYSCON_ADCCLKDIV_DIV_MASK) frequency = CLOCK_GetFreq(DEMO_ADC_CLOCK_SOURCE) / CLOCK_GetClkDivider(kCLOCK_DivAdcClk); #else frequency = CLOCK_GetFreq(DEMO_ADC_CLOCK_SOURCE); #endif/* SYSCON_ADCCLKDIV_DIV_MASK */ /* Calibration after power up. */ if (ADC_DoSelfCalibration(DEMO_ADC_BASE, frequency)) #endif/* FSL_FEATURE_ADC_HAS_CALIB_REG */ { PRINTF("ADC_DoSelfCalibration() Done.\r\n"); } else { PRINTF("ADC_DoSelfCalibration() Failed.\r\n"); } #endif/* FSL_FEATURE_ADC_HAS_NO_CALIB_FUNC */ /* Configure the converter and work mode. */ ADC_Configuration(); PRINTF("Configuration Done.\r\n"); #ifdefined(FSL_FEATURE_ADC_HAS_CTRL_RESOL) & FSL_FEATURE_ADC_HAS_CTRL_RESOL PRINTF("ADC Full Range: %d\r\n", g_Adc_12bitFullRange); #endif/* FSL_FEATURE_ADC_HAS_CTRL_RESOL */ GPIO_PortInit(GPIO, BOARD_LED_PORT); GPIO_PinInit(GPIO, BOARD_LED_PORT, 11, &led_config); GPIO_PinInit(GPIO, BOARD_LED_PORT, 10, &led_config); OLED_Init(); OLED_Clear(); OLED_ShowString(0,0,"K32W061 TEST",16); if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } SysTick_DelayTicks(1000U); OLED_ShowString(0,2,"adc=",16); while (1) { ADC_DoSoftwareTriggerConvSeqA(DEMO_ADC_BASE); /* Wait for the converter to be done. */ while (!ADC_GetChannelConversionResult(DEMO_ADC_BASE, DEMO_ADC_SAMPLE_CHANNEL_NUMBER, &adcResultInfoStruct)) { } OLED_ShowNum(32,2,adcResultInfoStruct.result,4,16); SysTick_DelayTicks(1000U); } }
复制代码由于在数据采集过程中,需要一定的转换时间,且数据采集也是有时间间隔要求的,故需要在程序中添加一个延时函数,以控制采样间隔。
经编译和下载,其执行效果如图3所示,通过电位器的调节可改变模拟信号的输入值。
![3.jpg 3.jpg](https://static.assets-stash.eet-china.com/forum/202109/17/000444voqnk994kx8otp2q.jpg)
![3b.jpg 3b.jpg](https://static.assets-stash.eet-china.com/forum/202109/17/000444nfnmhkinvth16m1v.jpg)
图3运行效果
动画演示3:(文件大小受限,无法上传)
4.UART
程序通讯是一种常用的功能,尤其是在未配置其它外设的情况下,串口几乎是唯一的观察工具。此外,设备间的数据共享也是靠串行通讯来完成的。
这里我们是使用串口来控制MP3模块的播放,该模块的实物如图4所示,图5是引脚的用途。
![4.jpg 4.jpg](https://static.assets-stash.eet-china.com/forum/202109/17/000444bjhxs6jdr4vo14s1.jpg)
图4 模块外观
![5.jpg 5.jpg](https://static.assets-stash.eet-china.com/forum/202109/17/000444duqnhfbznql9n09p.jpg)
图5 引脚用途
在实际的使用中,我们只需连接电源引脚、扬声器引脚及串口的接收引脚。
控制MP3播放的主程序如下:
#include"board.h"#include"fsl_usart.h" #include"pin_mux.h" #include<stdbool.h> #define DEMO_USART USART0 #define DEMO_USART_CLK_SRC kCLOCK_Fro32M #define DEMO_USART_CLK_FREQ CLOCK_GetFreq(DEMO_USART_CLK_SRC) uint8_t cmd3[10] = {0X7E, 0xFF, 0x06, 0X03, 0x00, 0x00, 0x01, 0xFE, 0xF7, 0XEF}; uint8_t rxbuff[20] = {0}; intmain(void) { uint8_t ch; usart_config_t config; /* Security code to allow debug access */ SYSCON->CODESECURITYPROT = 0x87654320; /* attach clock for USART(debug console) */ CLOCK_AttachClk(BOARD_DEBUG_UART_CLK_ATTACH); /* reset FLEXCOMM for USART */ RESET_PeripheralReset(kFC0_RST_SHIFT_RSTn); BOARD_BootClockRUN(); BOARD_InitDebugConsole(); BOARD_InitPins(); USART_GetDefaultConfig(&config); config.baudRate_Bps = 9600U; config.enableTx = true; config.enableRx = true; USART_Init(DEMO_USART, &config, DEMO_USART_CLK_FREQ); USART_WriteBlocking(DEMO_USART, txbuff, sizeof(txbuff) - 1); while (1) { USART_ReadBlocking(DEMO_USART, &ch, 1); USART_WriteBlocking(DEMO_USART, &ch, 1); } }
复制代码由于MP3模块的通讯速率为9600bps,故将串行通讯的波特率设为9600。
![6.jpg 6.jpg](https://static.assets-stash.eet-china.com/forum/202109/17/000444krgy96kdk1795grz.jpg)
图6 播放控制