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运行效果
动画演示1:
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运行效果
动画演示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运行效果
动画演示3:(文件大小受限,无法上传)
4.UART
程序通讯是一种常用的功能,尤其是在未配置其它外设的情况下,串口几乎是唯一的观察工具。此外,设备间的数据共享也是靠串行通讯来完成的。
这里我们是使用串口来控制MP3模块的播放,该模块的实物如图4所示,图5是引脚的用途。
图4 模块外观
图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 播放控制