yin_wu_qing

  • 2025-03-20
  • 发表了主题帖: 【KW41Z开发板测评】⑥微信小程序控制台灯

    本帖最后由 yin_wu_qing 于 2025-3-20 22:26 编辑       根据上期的⑤蓝牙调试工具控制台灯调试结果,今天来分享一下,使用个人微信的小程序来控制台灯。由于是基于蓝牙通讯,因此用户无需打开WiFi或移动数据连接开关。小程序比较流行,用户无需下载安装第三方的应用包,只需要微信扫码或搜索即可使用,易用性强。       一、搭建开发环境       首先要下载“微信开发者工具”,可通过下载之家 免费下载、安装。注册一个账号,或者直接使用微信扫码登录。      微信官方提供了诸多保姆级网页文档教程,开发者可移步:微信官方文档 ● 小程序进行系统性学习了解。      在熟悉了基本的概念后,开发者通过连接硬件能力-蓝牙篇网页,在页面最底下可获取标准模板例程,无需下载,点击完即可加载到“微信开发者工具”的IDE中。然后再将加载进来的工程文件保存到个人创建好的工程目录下。       从示例代码中可进一步了解小程序设计的工程目录结构,用到Javascript与html语言,.js文件是页面逻辑处理部分的源码,.wxml文件是描述页面结构,.json是关于页面配置的,.wxss是关于页面样式表的设置。笔者在此示例工程上,创建一个新的页面,里面展示一个开关按钮、一个显示温度、湿度的控件。           二、代码完善     根据页面设计需求,创建的device.js、device.json、device.wxml、device.wxss源码分享如下:    ① device.js const app = getApp() function inArray(arr, key, val) { for (let i = 0; i < arr.length; i++) { if (arr[i][key] === val) { return i; } } return -1; } // ArrayBuffer转16进度字符串示例 function ab2hex(buffer) { var hexArr = Array.prototype.map.call( new Uint8Array(buffer), function (bit) { return ('00' + bit.toString(16)).slice(-2) } ) return hexArr.join(''); } Page({ data: { deviceId: null, name:null, inputValue: '', connected: false, chs: [], temperature: '20', humidity: '60', switchChecked: false, // 开关初始状态为关闭 }, onLoad: function(options) { const deviceId = app.globalData.deviceId; const name = app.globalData.name; console.log('name:' + name) console.log('deviceId:' + deviceId) wx.createBLEConnection({ deviceId, success: (res) => { this.setData({ connected: true, name, deviceId, }) this.getBLEDeviceServices(deviceId) } }) }, getBLEDeviceServices(deviceId) { wx.getBLEDeviceServices({ deviceId, success: (res) => { for (let i = 0; i < res.services.length; i++) { if (res.services[i].isPrimary) { this.getBLEDeviceCharacteristics(deviceId, res.services[i].uuid) return } } } }) }, getBLEDeviceCharacteristics(deviceId, serviceId) { wx.getBLEDeviceCharacteristics({ deviceId, serviceId, success: (res) => { console.log('getBLEDeviceCharacteristics success', res.characteristics) for (let i = 0; i < res.characteristics.length; i++) { let item = res.characteristics[i] if (item.properties.read) { wx.readBLECharacteristicValue({ deviceId, serviceId, characteristicId: item.uuid, }) } if (item.properties.write) { this.setData({ canWrite: true }) this._deviceId = deviceId this._serviceId = serviceId this._characteristicId = item.uuid this.writeBLECharacteristicValue() } if (item.properties.notify || item.properties.indicate) { wx.notifyBLECharacteristicValueChange({ deviceId, serviceId, characteristicId: item.uuid, state: true, }) } } }, fail(res) { console.error('getBLEDeviceCharacteristics', res) } }) // 操作之前先监听,保证第一时间获取数据 wx.onBLECharacteristicValueChange((characteristic) => { const idx = inArray(this.data.chs, 'uuid', characteristic.characteristicId) const data = {} if (idx === -1) { data[`chs[${this.data.chs.length}]`] = { uuid: characteristic.characteristicId, value: ab2hex(characteristic.value) } } else { data[`chs[${idx}]`] = { uuid: characteristic.characteristicId, value: ab2hex(characteristic.value) } } if(characteristic.characteristicId == 'E01C4B5E-1EEB-A15C-EEF4-5EBA0001FF01') { let dataView = new DataView(characteristic.value) const temp = (dataView.getUint8(0))*10 + dataView.getUint8(1); const hum = dataView.getUint8(2)*10 + dataView.getUint8(3); this.setData({ humidity: hum, temperature: temp, }) } this.setData(data); }) }, writeBLECharacteristicValue() { // 向蓝牙设备发送一个0x00的16进制数据 let buffer = new ArrayBuffer(2) let dataView = new DataView(buffer) dataView.setUint8(0, 0); dataView.setUint8(0, 1); wx.writeBLECharacteristicValue({ deviceId: this._deviceId, serviceId: this._serviceId, characteristicId: this._characteristicId, value: buffer, success (res) { console.log('writeBLECharacteristicValue success', res.errMsg) }, fail (err) { console.log('writeBLECharacteristicValue fail', err.errMsg) } }) }, switchChange: function (e) { // 获取开关改变后的状态值 const checked = e.detail.value; let buffer = new ArrayBuffer(2) let dataView = new DataView(buffer) dataView.setUint8(0, 0); if(checked){ // 向蓝牙设备发送一个0x00的16进制数据 dataView.setUint8(0, 0x31); }else{ dataView.setUint8(0, 0x30); } wx.writeBLECharacteristicValue({ deviceId: this._deviceId, serviceId: this._serviceId, characteristicId: this._characteristicId, value: buffer, success (res) { console.log('writeBLECharacteristicValue success', res.errMsg) }, fail (err) { console.log('writeBLECharacteristicValue fail', err.errMsg) } }) this.setData({ switchChecked: checked }); }, }) ② device.json { "usingComponents": {} } ③ device.wxml <view class="connected_info" wx:if="{{connected}}"> <view> <text>已连接到 {{name}}</text> <view class="operation"> <button wx:if="{{canWrite}}" size="mini" bindtap="writeBLECharacteristicValue">写数据</button> <button size="mini" bindtap="closeBLEConnection">断开连接</button> </view> </view> </view> <view class="container"> <view class="display-item"> <text>灯光:</text> </view> <switch checked="{{switchChecked}}" bindchange="switchChange" /> <view class="display-item"> <text>----------------------</text> </view> <!-- 温度显示控件 --> <view class="display-item"> <text>温度:</text> <text>{{temperature}}°C</text> </view> <!-- 湿度显示控件 --> <view class="display-item"> <text>湿度:</text> <text>{{humidity}}%RH</text> </view> </view> ④ device.wxss .container { display: flex; flex-direction: column; align-items: center; padding: 20rpx; } .switch { margin-bottom: 30rpx; } .display-item { display: flex; align-items: center; margin-bottom: 20rpx; } .display-item text:first-child { margin-right: 10rpx; font-weight: bold; } slider { width: 80%; margin: 30px 0; } 接下来,需要再修改index.js的Page页中跳转服务与参数保存函数入口,修改如下: const app = getApp() function inArray(arr, key, val) { for (let i = 0; i < arr.length; i++) { if (arr[i][key] === val) { return i; } } return -1; } // ArrayBuffer转16进度字符串示例 function ab2hex(buffer) { var hexArr = Array.prototype.map.call( new Uint8Array(buffer), function (bit) { return ('00' + bit.toString(16)).slice(-2) } ) return hexArr.join(''); } Page({ data: { devices: [], connected: false, chs: [], }, openBluetoothAdapter() { wx.openBluetoothAdapter({ success: (res) => { console.log('openBluetoothAdapter success', res) this.startBluetoothDevicesDiscovery() }, fail: (res) => { if (res.errCode === 10001) { wx.onBluetoothAdapterStateChange(function (res) { console.log('onBluetoothAdapterStateChange', res) if (res.available) { this.startBluetoothDevicesDiscovery() } }) } } }) }, getBluetoothAdapterState() { wx.getBluetoothAdapterState({ success: (res) => { console.log('getBluetoothAdapterState', res) if (res.discovering) { this.onBluetoothDeviceFound() } else if (res.available) { this.startBluetoothDevicesDiscovery() } } }) }, startBluetoothDevicesDiscovery() { if (this._discoveryStarted) { return } this._discoveryStarted = true wx.startBluetoothDevicesDiscovery({ allowDuplicatesKey: true, success: (res) => { console.log('startBluetoothDevicesDiscovery success', res) this.onBluetoothDeviceFound() }, }) }, stopBluetoothDevicesDiscovery() { wx.stopBluetoothDevicesDiscovery() }, onBluetoothDeviceFound() { wx.onBluetoothDeviceFound((res) => { res.devices.forEach(device => { if (!device.name && !device.localName) { return } const foundDevices = this.data.devices const idx = inArray(foundDevices, 'deviceId', device.deviceId) const data = {} if (idx === -1) { data[`devices[${foundDevices.length}]`] = device } else { data[`devices[${idx}]`] = device } this.setData(data) }) }) }, createBLEConnection(e) { const ds = e.currentTarget.dataset const deviceId = ds.deviceId const name = ds.name // 添加跳转函数 app.globalData.deviceId = deviceId; app.globalData.name = name; wx.navigateTo({ url: 'device' }) this.stopBluetoothDevicesDiscovery() }, closeBLEConnection() { wx.closeBLEConnection({ deviceId: this.data.deviceId }) this.setData({ connected: false, chs: [], canWrite: false, }) }, closeBluetoothAdapter() { wx.closeBluetoothAdapter() this._discoveryStarted = false }, }) 最后在app.js中添加全局变量用于传递参数: App({ globalData: { deviceId: "", name: "", chs: [], }, onLaunch: function () { } })       三、编译预览效果与结语      通过“微信开发者工具”编译后,预览上传,生成二维码后,使用手机端的微信扫码,即可更新为当前设计的小程序应用了,效果展示见底部视频,对之前使用蓝牙调试工具控制台灯的固件稍作修改,手机与板卡建立蓝牙连接后,台灯默认状态由原来的被点亮改成关灯状态,这样与小程序默认关闭状态同步。此次对FRDM-KW41Z开发板的评测到此结束,尽管板子有些年头,遇到的问题也比较怪,但体验下来,调试也比较方便,尤其是板卡无需外接JLink调试器,只需一个microUSB数据线就能在MCUXpresso IDE进行调试,NXP的IDE很方便,这点相信使用过的都深有体会。最后,感谢电子工程世界提供的“年终回炉”活动,让闲置的开发板“活”起来。 [localvideo]dbeefe7d656320222c33eb7751a0e6fd[/localvideo]

  • 2025-03-19
  • 发表了主题帖: 【KW41Z开发板测评】⑤蓝牙调试工具控制台灯

    本帖最后由 yin_wu_qing 于 2025-3-20 13:06 编辑 一、前言         前段时间比较忙,最近终于缓过来,而距离规定评测KW41Z开发板的时限越来越近了,今天来分享一下前段时间个人评测时遇到的一些问题与经验。承接上期的④驱动直流电机的帖子,预期是通过该功能的实现,然后将其主干函数接口移入蓝牙串口demo中,然而结合PWM0四路通道、PWM1两路通道、PWM2两路通道分布来看,有两个通道的管脚被复用成串口,还有几个复用管脚没有被引出到两边排座,因此可用来兼顾“bluetooth_wireless_uart”工程的原本功能后,再调试出两路PWM显得比较紧凑,加之调试当中发现,板子两边的排座接口绝大多数是需要自行焊接好0Ω的电阻才能正常使用,这些结合官方提供的原理图可知,如下图标识的红色框。 二、工程配置          根据上述,咱也暂时不考虑将PWM功能接口移入蓝牙串口工程,在原计划上稍作更改,先实现一个蓝牙控制台灯功能。将SDK中的“frdmkw41z_wireless_examples_bluetooth_wireless_uart_bm”工程导出至MCUXpresso IDE中,然后编译下载到开发板中运行,发现即可以通过手机端的“IoT_Toolbox”工具去发送字符,然后在PC端的串口工具上接收打印;也可以通过PC端的串口调试助手给开发板发数据,然后在手机端的App显示接收数据,这样看来,K41Z的“bluetooth_wireless_uart_bm”工程似乎是K41Z相当于一个蓝牙数据透传网络中的“中间桥梁”。因此在此基础上去控制板上的某一个管脚输出高低电平,显得尤为简单。然而万万没想到的是也没那么顺利,听我娓娓道来。 ①、也不知道当初这款板是为何设计的,两边的排座是不能直接使用的,因为板上都没焊接相应的贴片电阻。于是本人使用PTC19做为将来通过蓝牙来控制的GPIO口,按照原理图连接关系,需要将SH15短接,这里使用烙铁在SH15处焊接了根导线,正如下图所示。 ②、接下来配置PTC19做为GPIOC_19,并初始化。 ③、在BleApp_ReceivedUartStream()串口接收函数中添加逻辑处理代码。 三、代码完善 pin_mux.c源文件中,将PTC19添加至LED初始化函数中。 #define PIN0_IDX 0u /*!< Pin number for pin 0 in a port */ #define PIN1_IDX 1u /*!< Pin number for pin 1 in a port */ #define PIN18_IDX 18u /*!< Pin number for pin 18 in a port */ #define PIN19_IDX 19u /*!< Pin number for pin 19 in a port */ /* * TEXT BELOW IS USED AS SETTING FOR THE PINS TOOL ***************************** BOARD_InitLEDs: - options: {coreID: singlecore, enableClock: 'true'} - pin_list: - {pin_num: '16', peripheral: GPIOB, signal: 'GPIO, 0', pin_signal: PTB0/LLWU_P8/XTAL_OUT_EN/I2C0_SCL/CMP0_OUT/TPM0_CH1/CLKOUT} - {pin_num: '37', peripheral: GPIOC, signal: 'GPIO, 1', pin_signal: PTC1/ANT_B/I2C0_SDA/UART0_RTS_b/TPM0_CH2/BLE_RF_ACTIVE} - {pin_num: '7', peripheral: GPIOA, signal: 'GPIO, 19', pin_signal: TSI0_CH13/ADC0_SE5/PTA19/LLWU_P7/SPI1_PCS0/TPM2_CH1} - {pin_num: '6', peripheral: GPIOA, signal: 'GPIO, 18', pin_signal: TSI0_CH12/PTA18/LLWU_P6/SPI1_SCK/TPM2_CH0} - {pin_num: '47', peripheral: GPIOC, signal: 'GPIO, 18', pin_signal: TSI0_CH6/PTC18/LLWU_P2/SPI0_SIN/I2C1_SDA/UART0_TX/BSM_DATA/DTM_TX} * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR THE PINS TOOL *** */ /*FUNCTION********************************************************************** * * Function Name : BOARD_InitLEDs * Description : Configures pin routing and optionally pin electrical features. * *END**************************************************************************/ void BOARD_InitLEDs(void) { CLOCK_EnableClock(kCLOCK_PortA); /* Port A Clock Gate Control: Clock enabled */ CLOCK_EnableClock(kCLOCK_PortB); /* Port B Clock Gate Control: Clock enabled */ CLOCK_EnableClock(kCLOCK_PortC); /* Port C Clock Gate Control: Clock enabled */ PORT_SetPinMux(PORTA, PIN18_IDX, kPORT_MuxAsGpio); /* PORTA18 (pin 6) is configured as PTA18 */ PORT_SetPinMux(PORTA, PIN19_IDX, kPORT_MuxAsGpio); /* PORTA19 (pin 7) is configured as PTA19 */ PORT_SetPinMux(PORTB, PIN0_IDX, kPORT_MuxAsGpio); /* PORTB0 (pin 16) is configured as PTB0 */ PORT_SetPinMux(PORTC, PIN1_IDX, kPORT_MuxAsGpio); /* PORTC1 (pin 37) is configured as PTC1 */ PORT_SetPinMux(PORTC, PIN18_IDX, kPORT_MuxAsGpio); /* PORTC18 (pin 47) is configured as PTC18 */ PORT_SetPinMux(PORTC, PIN19_IDX, kPORT_MuxAsGpio); /* Add use to driver extern LED */ } LED.c源文件中,初始化函数中添加对PTC19的初始化。 gpioOutputPinConfig_t Externdled = { .gpioPort = gpioPort_C_c, .gpioPin = 19, .outputLogic = 0, .slewRate = pinSlewRate_Slow_c, .driveStrength = pinDriveStrength_High_c }; /****************************************************************************** * Name: LED_Init * Description: Initialize the LED module * Parameters: - * Return: - ******************************************************************************/ void LED_Init ( void ) { BOARD_InitLEDs(); (void)GpioOutputPinInit(ledPins, gLEDsOnTargetBoardCnt_c); GpioSetPinOutput(&Externdled); #if gLedRgbEnabled_d LED_RgbLedInit(); #endif /* allocate a timer for use in flashing LEDs */ #if gTMR_Enabled_d mLEDTimerID = TMR_AllocateTimer(); #endif #if gLedRgbEnabled_d && gRgbLedDimmingEnabled_d && gTMR_Enabled_d /* allocate a timer for use in RGB dimming */ mRGBLedTimerID = TMR_AllocateTimer(); mRbgDimInfo.ongoing = FALSE; mRbgDimInfo.interval = gRgbLedDimDefaultInterval_c; #endif /* gLedRgbEnabled_d && gRgbLedDimmingEnabled_d && gTMR_Enabled_d */ } wireless_uart.c源文件中的static void BleApp_ReceivedUartStream(uint8_t *pStream, uint16_t streamLength)函数中进行逻辑处理。 static void BleApp_ReceivedUartStream(uint8_t *pStream, uint16_t streamLength) { uint8_t *pBuffer = NULL; /* Allocate buffer for asynchronous write */ pBuffer = MEM_BufferAlloc(streamLength); if(pStream[0]) { if(pStream[0]== 0x31) { GPIO_SetPinsOutput(GPIOC,19); } else if(pStream[0]==0x30) { GPIO_ClearPinsOutput(GPIOC,19); } } if (pBuffer != NULL) { Serial_AsyncWrite(gAppSerMgrIf, pStream, streamLength, Uart_TxCallBack, pBuffer); } } 为了更好的用户体验,再将断开蓝牙后、再次广播时,将PTC19输出低,添加GPIO_ClearPinsOutput(GPIOC,19); 四、工程编译调试 1、基于以上操作,故将外接的LED连接到PTC19的排针座子上,结果编译后,将程序下载到板子上运行,短按一下板上的SW4,让开发板进入广播状态,然后手机端打开蓝牙、GPS,打开蓝牙调试助手,即可搜索到名为“NXP_WU”的蓝牙设备。连接后发现有创建三个服务,可通过Unknown Service服务发送字符给开发板。结果连接在PTC19管脚处的LED灯没任何反应,反而点亮了RGB灯的第一个管脚,即点亮了红色。       这就有点费解了,而且高低电平与代码中操作PTC19管脚的逻辑刚好相反。再结合pin_mux.c源码中的管脚复用情况,电路原理图的管脚分布,跳线帽设置也是出厂时的状态,一段时间了也没研究出是何原因! 2、既然可以间接控制PTC1管脚的高低电平状态,这里笔者索性将控制台灯的管脚设置在TP24测试点上(见上面RGB灯原理图),将杜邦线焊接在该点上,如下图所示: 3、在某宝上掏了几个模块与5V日光灯,做为实现蓝牙控制台灯的硬件资源。连接的示意图如下: 所对应的实物硬件连接如下: 4、运行代码,使用”蓝牙调试助手“App给K41Z发有效字符,从而实现蓝牙远程控制台灯,效果见底下视频。 五、小结       根据实际调试结果来看,PTC19管脚的信号控制似乎与PTC1(TP24)有关联,因为代码中逻辑处理部分是对PTC19管脚进行高低电平的控制,而实际应用是对PTC1起作用,通过焊接导线短接SH15处的PTC19排针座子并没有预设电平输出。尽管这块板比较陈旧,但想必硬件上也不会有大的问题吧?不然不会搜索一番,也没搜索到遇上类似的问题、现象。不知道咱们坛友有没有遇到类似的问题,欢迎回帖讨论。 [localvideo]e4b922818c55eb75fadc50b98e60bba5[/localvideo]  

  • 2025-02-26
  • 回复了主题帖: 【KW41Z开发板测评】④驱动直流电机

    freebsder 发表于 2025-2-25 16:24 这板子出的有些年头了 NXP官方已经没生产了吧,有些年头了,资料都显示是2017年的。

  • 2025-02-24
  • 发表了主题帖: 【KW41Z开发板测评】④驱动直流电机

         前面分享了驱动TFT-LCD屏,本期使用KW41Z驱动12V直流电机。由于KW41Z支持3路TPM,可以通过GPIO口的复用配置成PWM输出管脚。开发板的主体框架如下:      再者开发板支持BLE4.2,Zigbee 3.0,Thread网络协议栈,因此可以做一些远程控制电机类产品,使产品功耗更低,更智能化。前段时间在“bluetooth_wireless_uart”工程上调试,计划通过手机app端发送字符来控制PWM输出占空比,无奈调试后仍然存有bug,此次使用PORTA18、PORTA19管脚复用为TPM2的输出通道,串口调试助手做为上位机,实现对两位直流电机的转速控制。        驱动直流电机,这里不得不引荐一下L298N电机驱动模块,L298N模块不仅价格低廉,而且易于使用。它能驱动2A至4A的大功率直流电机和步进电机,具备H桥结构,支持正反转及调速。通过单片机控制输入端逻辑电平,可实现电机的精确控制。同时,模块内置光耦隔离,确保系统稳定性。模块的正视图如下: 管脚说明: Output A:接DC电机1或步进电机的A+和A-; Output B:接DC电机2或步进电机的B+和B-;   12V Enable:如果使用输入电源大于12V的电源,请将跳线帽短接。输入电源小于12V时去除跳线帽可以提供5V电源输出; +5V Power:当输入电源小于12V时且12V Enable处于断开状态,可以提供+5V电源输出; Power Gnd:电源地; +12V Power:连接电机电源,最大35V。输入电压大于12V时,请短接12V Enable针脚上的跳线帽; A/B Enable:可用于输入PWM脉宽调制信号对电机进行调速控制。输入信号端IN1接高电平输入端IN2接低电平,电机M1正转。(如果信号端IN1接低电平, IN2接高电平,电机M1反转。)控制另一台电机是同样的方式,输入信号端IN3接高电平,输入端IN4接低电平,电机M2正转。(反之则反转),PWM信号端A控制M1调速,PWM信号端B控制M2调速。可参考下图表:       这里笔者暂且不考虑驱动电机的转向,因此只需两路PWM输出即可,实物连接如下:           编写代码,通过键盘输入“0”~“99”任意整数值到上位机串口调试助手中,发送给KW41Z,从而改变这两路PWM输出的占空比。 pin_mux.c #include "fsl_common.h" #include "fsl_port.h" #include "pin_mux.h" #define PIN6_IDX 6u /*!< Pin number for pin 6 in a port */ #define PIN7_IDX 7u /*!< Pin number for pin 7 in a port */ #define PIN18_IDX 18u /*!< Pin number for pin 18 in a port */ #define PIN19_IDX 19u /*!< Pin number for pin 19 in a port */ #define SOPT4_TPM2CH0SRC_TPM 0x00u /*!< TPM2 Channel 0 Input Capture Source Select: TPM2_CH0 signal */ #define SOPT5_LPUART0RXSRC_LPUART_RX 0x00u /*!< LPUART0 Receive Data Source Select: LPUART_RX pin */ /*FUNCTION********************************************************************** * * Function Name : BOARD_InitPins * Description : Configures pin routing and optionally pin electrical features. * *END**************************************************************************/ void BOARD_InitPins(void) { CLOCK_EnableClock(kCLOCK_PortA); /* Port A Clock Gate Control: Clock enabled */ CLOCK_EnableClock(kCLOCK_PortC); /* Port C Clock Gate Control: Clock enabled */ PORT_SetPinMux(PORTA, PIN18_IDX, kPORT_MuxAlt5); /* PORTA18 (pin 6) is configured as TPM2_CH0 */ PORT_SetPinMux(PORTA, PIN19_IDX, kPORT_MuxAlt5); /* PORTA19 (pin 7) is configured as TPM2_CH1 */ PORT_SetPinMux(PORTC, PIN6_IDX, kPORT_MuxAlt4); /* PORTC6 (pin 42) is configured as UART0_RX */ PORT_SetPinMux(PORTC, PIN7_IDX, kPORT_MuxAlt4); /* PORTC7 (pin 43) is configured as UART0_TX */ SIM->SOPT4 = ((SIM->SOPT4 & (~(SIM_SOPT4_TPM2CH0SRC_MASK))) /* Mask bits to zero which are setting */ | SIM_SOPT4_TPM2CH0SRC(SOPT4_TPM2CH0SRC_TPM) /* TPM2 Channel 0 Input Capture Source Select: TPM2_CH0 signal */ ); SIM->SOPT5 = ((SIM->SOPT5 & (~(SIM_SOPT5_LPUART0RXSRC_MASK))) /* Mask bits to zero which are setting */ | SIM_SOPT5_LPUART0RXSRC(SOPT5_LPUART0RXSRC_LPUART_RX) /* LPUART0 Receive Data Source Select: LPUART_RX pin */ ); } main.c #include "fsl_debug_console.h" #include "board.h" #include "fsl_tpm.h" #include "fsl_device_registers.h" #include "pin_mux.h" #include <stdbool.h> #include "clock_config.h" /******************************************************************************* * Definitions ******************************************************************************/ #define BOARD_TPM_BASEADDR TPM2 #define BOARD_FIRST_TPM_CHANNEL 0U #define BOARD_SECOND_TPM_CHANNEL 1U /* Get source clock for TPM driver */ #define TPM_SOURCE_CLOCK CLOCK_GetFreq(kCLOCK_McgFllClk) /******************************************************************************* * Variables ******************************************************************************/ volatile uint8_t getDutyValue = 0U; volatile uint8_t updatedDutycycle = 1U; /******************************************************************************* * Code ******************************************************************************/ /*! * [url=home.php?mod=space&uid=159083]@brief[/url] Main function */ int main(void) { tpm_config_t tpmInfo; tpm_chnl_pwm_signal_param_t tpmParam[2]; /* Configure tpm params with frequency 24kHZ */ tpmParam[0].chnlNumber = (tpm_chnl_t)BOARD_FIRST_TPM_CHANNEL; tpmParam[0].level = kTPM_LowTrue; tpmParam[0].dutyCyclePercent = updatedDutycycle; tpmParam[1].chnlNumber = (tpm_chnl_t)BOARD_SECOND_TPM_CHANNEL; tpmParam[1].level = kTPM_LowTrue; tpmParam[1].dutyCyclePercent = updatedDutycycle; /* Board pin, clock, debug console init */ BOARD_InitPins(); BOARD_BootClockRUN(); BOARD_InitDebugConsole(); /* Select the clock source for the TPM counter as MCGPLLCLK */ CLOCK_SetTpmClock(1U); /* Print a note to terminal */ PRINTF("\r\nTPM example to output PWM on 2 channels\r\n"); PRINTF("\r\nIf an LED is connected to the TPM pin, you will see a change in LED brightness if you enter different values"); PRINTF("\r\nIf no LED is connected to the TPM pin, then probe the signal using an oscilloscope"); TPM_GetDefaultConfig(&tpmInfo); /* Initialize TPM module */ TPM_Init(BOARD_TPM_BASEADDR, &tpmInfo); TPM_SetupPwm(BOARD_TPM_BASEADDR, tpmParam, 2U, kTPM_EdgeAlignedPwm, 24000U, TPM_SOURCE_CLOCK); TPM_StartTimer(BOARD_TPM_BASEADDR, kTPM_SystemClock); while (1) { do { PRINTF("\r\nPlease enter a value to update the Duty cycle:\r\n"); PRINTF("Note: The range of value is 0 to 99.\r\n"); PRINTF("For example: If enter '55', the duty cycle will be set to 55 percent.\r\n"); PRINTF("Value:"); SCANF("%d",&getDutyValue); PRINTF("%d", getDutyValue); PRINTF("\r\n"); if(getDutyValue > 99) getDutyValue = 0; } while (getDutyValue > 99U); updatedDutycycle = getDutyValue; /* Start PWM mode with updated duty cycle */ TPM_UpdatePwmDutycycle(BOARD_TPM_BASEADDR, (tpm_chnl_t)BOARD_FIRST_TPM_CHANNEL, kTPM_EdgeAlignedPwm,updatedDutycycle); TPM_UpdatePwmDutycycle(BOARD_TPM_BASEADDR, (tpm_chnl_t)BOARD_SECOND_TPM_CHANNEL, kTPM_EdgeAlignedPwm,updatedDutycycle); PRINTF("The duty cycle was successfully updated!\r\n"); } }       驱动电机的效果展示如下视频,视频中不难发现,相同占空比输出,而电机转速不尽相同。这里是由于两个电机的转轴不同,因而影响电机转速。 [localvideo]770b3e68b211ce6ecdd8e35f3d2457dc[/localvideo]

  • 2025-02-15
  • 发表了主题帖: 【KW41Z开发板测评】③驱动TFT-LCD彩屏

    一、概述     承接上期的【KW41Z开发板测评】②PWM输出呼吸灯帖子,由于春节放假期间事儿比较多,因此有段没更新贴子了,趁周末来补补。     本次是在上期的呼吸灯工程中实现驱动TFT-LCD屏。     前期资源准备    自购一块RGB串口屏,得捷电子商城上架:AFL128160A0-1.77N12NTM-ANO,屏为1.77寸,点像素:128X160,接口为SPI,驱动控制芯片为:ST7735S,这类屏兼容性、性价比非常友好。驱动该屏可使用GPIO口软件模拟SPI通信去驱动,也可采用SPI硬件接口去驱动,当然软件模拟方式易于移植,不受IO口的限制,但刷新数据没有硬件来得快,这是众所周知的,笔者此次采用软件模拟方式驱屏。      接下来寻找板上硬件接口,根据快速入门手册可知开发板正面的硬件资源分布如下图。     再结合《KW41ZData Sheet》可知管脚复用关系,这里笔者采用J1、J2排座上的PTC2、PTC3、PTC16~PTC19、P3V3、GND接口。 二、硬件连接     开发板与TFT-LCD屏的引脚连接对应关系如下:        笔者使用2.54mm杜邦线将管脚间对应连接上,至此硬件接口连接完毕。 三、部分参考代码 pin_mux.c #include "fsl_common.h" #include "fsl_port.h" #include "pin_mux.h" #include "fsl_gpio.h" #define PIN6_IDX 6u /*!< Pin number for pin 6 in a port */ #define PIN7_IDX 7u /*!< Pin number for pin 7 in a port */ #define PIN18_IDX 18u /*!< Pin number for pin 18 in a port */ #define SOPT4_TPM2CH0SRC_TPM 0x00u /*!< TPM2 Channel 0 Input Capture Source Select: TPM2_CH0 signal */ #define SOPT5_LPUART0RXSRC_LPUART_RX 0x00u /*!< LPUART0 Receive Data Source Select: LPUART_RX pin */ void BOARD_InitPins(void) { CLOCK_EnableClock(kCLOCK_PortA); /* Port A Clock Gate Control: Clock enabled */ CLOCK_EnableClock(kCLOCK_PortC); /* Port C Clock Gate Control: Clock enabled */ gpio_pin_config_t OUT_LOW_config = { .pinDirection = kGPIO_DigitalOutput, .outputLogic = 0U, }; gpio_pin_config_t OUT_HIGH_config = { .pinDirection = kGPIO_DigitalOutput, .outputLogic = 1U, }; GPIO_PinInit(GPIOC, 2U, &OUT_LOW_config); GPIO_PinInit(GPIOC, 3U, &OUT_LOW_config); GPIO_PinInit(GPIOC, 16U, &OUT_LOW_config); GPIO_PinInit(GPIOC, 17U, &OUT_LOW_config); GPIO_PinInit(GPIOC, 18U, &OUT_LOW_config); GPIO_PinInit(GPIOC, 19U, &OUT_HIGH_config); PORT_SetPinMux(PORTC,2u,kPORT_MuxAsGpio); PORT_SetPinMux(PORTC,3u,kPORT_MuxAsGpio); PORT_SetPinMux(PORTC,16u,kPORT_MuxAsGpio); PORT_SetPinMux(PORTC,17u,kPORT_MuxAsGpio); PORT_SetPinMux(PORTC,18u,kPORT_MuxAsGpio); PORT_SetPinMux(PORTC,19u,kPORT_MuxAsGpio); PORT_SetPinMux(PORTA, PIN18_IDX, kPORT_MuxAlt5); /* PORTA18 (pin 6) is configured as TPM2_CH0 */ PORT_SetPinMux(PORTC, PIN6_IDX, kPORT_MuxAlt4); /* PORTC6 (pin 42) is configured as UART0_RX */ PORT_SetPinMux(PORTC, PIN7_IDX, kPORT_MuxAlt4); /* PORTC7 (pin 43) is configured as UART0_TX */ SIM->SOPT4 = ((SIM->SOPT4 & (~(SIM_SOPT4_TPM2CH0SRC_MASK))) /* Mask bits to zero which are setting */ | SIM_SOPT4_TPM2CH0SRC(SOPT4_TPM2CH0SRC_TPM) /* TPM2 Channel 0 Input Capture Source Select: TPM2_CH0 signal */ ); SIM->SOPT5 = ((SIM->SOPT5 & (~(SIM_SOPT5_LPUART0RXSRC_MASK))) /* Mask bits to zero which are setting */ | SIM_SOPT5_LPUART0RXSRC(SOPT5_LPUART0RXSRC_LPUART_RX) /* LPUART0 Receive Data Source Select: LPUART_RX pin */ ); } tpm_simple_pwm.c #include "fsl_debug_console.h" #include "board.h" #include "fsl_tpm.h" #include "pin_mux.h" #include "lcd_init.h" #include "lcd.h" #include "pic.h" #define BOARD_TPM_BASEADDR TPM2 #define BOARD_TPM_CHANNEL 0U /* Interrupt to enable and flag to read; depends on the TPM channel used */ #define TPM_CHANNEL_INTERRUPT_ENABLE kTPM_Chnl0InterruptEnable #define TPM_CHANNEL_FLAG kTPM_Chnl0Flag /* Interrupt number and interrupt handler for the TPM instance used */ #define TPM_INTERRUPT_NUMBER TPM2_IRQn #define TPM_LED_HANDLER TPM2_IRQHandler /* Get source clock for TPM driver */ #define TPM_SOURCE_CLOCK CLOCK_GetFreq(kCLOCK_McgFllClk) #define Year 2025 volatile bool brightnessUp = true; /* Indicate LED is brighter or dimmer */ volatile uint8_t updatedDutycycle = 10U; volatile uint8_t getCharValue = 0U; volatile uint32_t g_systickCounter; uint8_t dutyCycle = 0; uint8_t var = 0; void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } } void Display_title(void) { SysTick_DelayTicks(1U); LCD_Fill(0,0,LCD_W,LCD_H,WHITE); LCD_ShowIntNum(8,10,Year,4,RED,BLACK,16); LcdShow16x16Hz(40,10,0,RED,BLACK);//"蛇" LcdShow16x16Hz(56,10,1,RED,BLACK);//"年" LcdShow16x16Hz(72,10,2,RED,BLACK);//"的" LcdShow16x16Hz(88,10,3,RED,BLACK);//"祝" LcdShow16x16Hz(104,10,4,RED,BLACK);//"福" LcdShow16x16Hz(8,35,5,GREEN,BLACK);//"巳" LcdShow16x16Hz(24,35,6,GREEN,BLACK);//"巳" LcdShow16x16Hz(40,35,7,GREEN,BLACK);//"如" LcdShow16x16Hz(56,35,8,GREEN,BLACK);//"意" LcdShow16x16Hz(8,60,9,GREEN,BLACK);//"生" LcdShow16x16Hz(24,60,10,GREEN,BLACK);//"生" LcdShow16x16Hz(40,60,11,GREEN,BLACK);//"不" LcdShow16x16Hz(56,60,12,GREEN,BLACK);//"息" LcdShow16x16Hz(8,85,13,GREEN,BLACK);//"工" LcdShow16x16Hz(24,85,14,GREEN,BLACK);//"程" LcdShow16x16Hz(40,85,15,GREEN,BLACK);//"世" LcdShow16x16Hz(56,85,16,GREEN,BLACK);//"界" LcdShow16x16Hz(8,110,17,GREEN,BLACK);//"再" LcdShow16x16Hz(24,110,18,GREEN,BLACK);//"创" LcdShow16x16Hz(40,110,19,GREEN,BLACK);//"佳" LcdShow16x16Hz(56,110,20,GREEN,BLACK);//"绩" LCD_ShowString(20,142,"2025-02-14",BLUE,LGRAY,16,0); SysTick_DelayTicks(3000U); } int main(void) { tpm_config_t tpmInfo; tpm_chnl_pwm_signal_param_t tpmParam; tpm_pwm_level_select_t pwmLevel = kTPM_LowTrue; /* Configure tpm params with frequency 24kHZ */ tpmParam.chnlNumber = (tpm_chnl_t)BOARD_TPM_CHANNEL; tpmParam.level = pwmLevel; tpmParam.dutyCyclePercent = updatedDutycycle; /* Board pin, clock, debug console init */ BOARD_InitPins(); BOARD_BootClockRUN(); BOARD_InitDebugConsole(); /* Select the clock source for the TPM counter as MCGPLLCLK */ CLOCK_SetTpmClock(1U); /* Set systick reload value to generate 1ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } TPM_GetDefaultConfig(&tpmInfo); /* Initialize TPM module */ TPM_Init(BOARD_TPM_BASEADDR, &tpmInfo); TPM_SetupPwm(BOARD_TPM_BASEADDR, &tpmParam, 1U, kTPM_CenterAlignedPwm, 24000U, TPM_SOURCE_CLOCK); TPM_StartTimer(BOARD_TPM_BASEADDR, kTPM_SystemClock); LCD_Init(); while (1) { LCD_Fill(0,0,LCD_W,LCD_H,LIGHTGREEN); LCD_ShowPicture(0,0,128,160,gImage_1); SysTick_DelayTicks(1000U); Display_title(); } } lcd_init.c #include "lcd_init.h" #include "board.h" extern void SysTick_DelayTicks(uint32_t n); /****************************************************************************** 函数说明:LCD串行数据写入函数 入口数据:dat 要写入的串行数据 返回值: 无 ******************************************************************************/ void LCD_Writ_Bus(u8 dat) { u8 i; LCD_CS_Clr(); for(i=0;i<8;i++) { LCD_SCLK_Clr(); if(dat&0x80) { LCD_MOSI_Set(); } else { LCD_MOSI_Clr(); } LCD_SCLK_Set(); dat<<=1; } LCD_CS_Set(); } /****************************************************************************** 函数说明:LCD写入数据 入口数据:dat 写入的数据 返回值: 无 ******************************************************************************/ void LCD_WR_DATA8(u8 dat) { LCD_Writ_Bus(dat); } /****************************************************************************** 函数说明:LCD写入数据 入口数据:dat 写入的数据 返回值: 无 ******************************************************************************/ void LCD_WR_DATA(u16 dat) { LCD_Writ_Bus(dat>>8); LCD_Writ_Bus(dat); } /****************************************************************************** 函数说明:LCD写入命令 入口数据:dat 写入的命令 返回值: 无 ******************************************************************************/ void LCD_WR_REG(u8 dat) { LCD_DC_Clr();//写命令 LCD_Writ_Bus(dat); LCD_DC_Set();//写数据 } /****************************************************************************** 函数说明:设置起始和结束地址 入口数据:x1,x2 设置列的起始和结束地址 y1,y2 设置行的起始和结束地址 返回值: 无 ******************************************************************************/ void LCD_Address_Set(u16 x1,u16 y1,u16 x2,u16 y2) { if(USE_HORIZONTAL==0) { LCD_WR_REG(0x2a);//列地址设置 LCD_WR_DATA(x1+2); LCD_WR_DATA(x2+2); LCD_WR_REG(0x2b);//行地址设置 LCD_WR_DATA(y1+1); LCD_WR_DATA(y2+1); LCD_WR_REG(0x2c);//储存器写 } else if(USE_HORIZONTAL==1) { LCD_WR_REG(0x2a);//列地址设置 LCD_WR_DATA(x1+2); LCD_WR_DATA(x2+2); LCD_WR_REG(0x2b);//行地址设置 LCD_WR_DATA(y1+1); LCD_WR_DATA(y2+1); LCD_WR_REG(0x2c);//储存器写 } else if(USE_HORIZONTAL==2) { LCD_WR_REG(0x2a);//列地址设置 LCD_WR_DATA(x1+1); LCD_WR_DATA(x2+1); LCD_WR_REG(0x2b);//行地址设置 LCD_WR_DATA(y1+2); LCD_WR_DATA(y2+2); LCD_WR_REG(0x2c);//储存器写 } else { LCD_WR_REG(0x2a);//列地址设置 LCD_WR_DATA(x1+1); LCD_WR_DATA(x2+1); LCD_WR_REG(0x2b);//行地址设置 LCD_WR_DATA(y1+2); LCD_WR_DATA(y2+2); LCD_WR_REG(0x2c);//储存器写 } } void LCD_Init(void) { LCD_RES_Clr();//复位 SysTick_DelayTicks(1); LCD_RES_Set(); SysTick_DelayTicks(1); LCD_BLK_Set();//打开背光 SysTick_DelayTicks(120); //************* Start Initial Sequence **********// LCD_WR_REG(0x11); //Sleep out SysTick_DelayTicks(120); //Delay 120ms //----------------ST7735S Frame Rate---------------------// LCD_WR_REG(0xB1); LCD_WR_DATA8(0x05); LCD_WR_DATA8(0x3C); LCD_WR_DATA8(0x3C); LCD_WR_REG(0xB2); LCD_WR_DATA8(0x05); LCD_WR_DATA8(0x3C); LCD_WR_DATA8(0x3C); LCD_WR_REG(0xB3); LCD_WR_DATA8(0x05); LCD_WR_DATA8(0x3C); LCD_WR_DATA8(0x3C); LCD_WR_DATA8(0x05); LCD_WR_DATA8(0x3C); LCD_WR_DATA8(0x3C); //--------------------End ST7735S Frame Rate---------------// LCD_WR_REG(0xB4); //Dot inversion LCD_WR_DATA8(0x03); //--------------------ST7735S Power Sequence---------------// LCD_WR_REG(0xC0); LCD_WR_DATA8(0x28); LCD_WR_DATA8(0x08); LCD_WR_DATA8(0x04); LCD_WR_REG(0xC1); LCD_WR_DATA8(0XC0); LCD_WR_REG(0xC2); LCD_WR_DATA8(0x0D); LCD_WR_DATA8(0x00); LCD_WR_REG(0xC3); LCD_WR_DATA8(0x8D); LCD_WR_DATA8(0x2A); LCD_WR_REG(0xC4); LCD_WR_DATA8(0x8D); LCD_WR_DATA8(0xEE); //-----------------End ST7735S Power Sequence--------------// LCD_WR_REG(0xC5); //VCOM LCD_WR_DATA8(0x1A); LCD_WR_REG(0x36); //MX, MY, RGB mode if(USE_HORIZONTAL==0)LCD_WR_DATA8(0x00); else if(USE_HORIZONTAL==1)LCD_WR_DATA8(0xC0); else if(USE_HORIZONTAL==2)LCD_WR_DATA8(0x70); else LCD_WR_DATA8(0xA0); //-----------------ST7735S Gamma Sequence------------------// LCD_WR_REG(0xE0); LCD_WR_DATA8(0x04); LCD_WR_DATA8(0x22); LCD_WR_DATA8(0x07); LCD_WR_DATA8(0x0A); LCD_WR_DATA8(0x2E); LCD_WR_DATA8(0x30); LCD_WR_DATA8(0x25); LCD_WR_DATA8(0x2A); LCD_WR_DATA8(0x28); LCD_WR_DATA8(0x26); LCD_WR_DATA8(0x2E); LCD_WR_DATA8(0x3A); LCD_WR_DATA8(0x00); LCD_WR_DATA8(0x01); LCD_WR_DATA8(0x03); LCD_WR_DATA8(0x13); LCD_WR_REG(0xE1); LCD_WR_DATA8(0x04); LCD_WR_DATA8(0x16); LCD_WR_DATA8(0x06); LCD_WR_DATA8(0x0D); LCD_WR_DATA8(0x2D); LCD_WR_DATA8(0x26); LCD_WR_DATA8(0x23); LCD_WR_DATA8(0x27); LCD_WR_DATA8(0x27); LCD_WR_DATA8(0x25); LCD_WR_DATA8(0x2D); LCD_WR_DATA8(0x3B); LCD_WR_DATA8(0x00); LCD_WR_DATA8(0x01); LCD_WR_DATA8(0x04); LCD_WR_DATA8(0x13); //-------------------End ST7735S Gamma Sequence--------------// LCD_WR_REG(0x3A); //65k mode LCD_WR_DATA8(0x05); LCD_WR_REG(0x29); //Display on } lcd_init.h #ifndef __LCD_INIT_H #define __LCD_INIT_H #include "board.h" #include "pin_mux.h" #define USE_HORIZONTAL 1 //设置横屏或者竖屏显示 0或1为竖屏 2或3为横屏 #if USE_HORIZONTAL==0||USE_HORIZONTAL==1 #define LCD_W 128 #define LCD_H 160 #else #define LCD_W 160 #define LCD_H 128 #endif #define BOARD_LCD_GPIO GPIOC #define BOARD_LCD_GPIO_SCLK_PIN (2U) #define BOARD_LCD_GPIO_CS_PIN (3U) #define BOARD_LCD_GPIO_RES_PIN (16U) #define BOARD_LCD_GPIO_DC_PIN (17U) #define BOARD_LCD_GPIO_MOSI_PIN (18U) #define BOARD_LCD_BLK_GPIO GPIOC #define BOARD_LCD_GPIO_BLK_PIN (19U) //-----------------LCD端口定义---------------- #define LCD_SCLK_Clr() GPIO_WritePinOutput(BOARD_LCD_GPIO,BOARD_LCD_GPIO_SCLK_PIN,0)//SCL SCLK #define LCD_SCLK_Set() GPIO_WritePinOutput(BOARD_LCD_GPIO,BOARD_LCD_GPIO_SCLK_PIN,1) #define LCD_CS_Clr() GPIO_WritePinOutput(BOARD_LCD_GPIO,BOARD_LCD_GPIO_CS_PIN,0)//CS #define LCD_CS_Set() GPIO_WritePinOutput(BOARD_LCD_GPIO,BOARD_LCD_GPIO_CS_PIN,1) #define LCD_MOSI_Clr() GPIO_WritePinOutput(BOARD_LCD_GPIO,BOARD_LCD_GPIO_MOSI_PIN,0)//SDA MOSI #define LCD_MOSI_Set() GPIO_WritePinOutput(BOARD_LCD_GPIO,BOARD_LCD_GPIO_MOSI_PIN,1) #define LCD_DC_Clr() GPIO_WritePinOutput(BOARD_LCD_GPIO,BOARD_LCD_GPIO_DC_PIN,0)//DC #define LCD_DC_Set() GPIO_WritePinOutput(BOARD_LCD_GPIO,BOARD_LCD_GPIO_DC_PIN,1) #define LCD_RES_Clr() GPIO_WritePinOutput(BOARD_LCD_GPIO,BOARD_LCD_GPIO_RES_PIN,0)//RES #define LCD_RES_Set() GPIO_WritePinOutput(BOARD_LCD_GPIO,BOARD_LCD_GPIO_RES_PIN,1) #define LCD_BLK_Clr() GPIO_WritePinOutput(BOARD_LCD_BLK_GPIO,BOARD_LCD_GPIO_BLK_PIN,0)//BLK #define LCD_BLK_Set() GPIO_WritePinOutput(BOARD_LCD_BLK_GPIO,BOARD_LCD_GPIO_BLK_PIN,1) void LCD_GPIO_Init(void);//初始化GPIO void LCD_Writ_Bus(u8 dat);//模拟SPI时序 void LCD_WR_DATA8(u8 dat);//写入一个字节 void LCD_WR_DATA(u16 dat);//写入两个字节 void LCD_WR_REG(u8 dat);//写入一个指令 void LCD_Address_Set(u16 x1,u16 y1,u16 x2,u16 y2);//设置坐标函数 void LCD_Init(void);//LCD初始化 #endif 四、图片字符显示效果      图片转C数组需要借助“Img2Lcd”工具,这里笔者将DIY画的bmp图片转C数组,参数设置详情如下: 显示中文字符,这里需要借助“PCtoLCD2002”工具,工具选项设置参数标记一下: 最终显示的效果呈现如下,使用GPIO口软件模拟SPI通信驱动,刷起图来的确没有硬件方式刷得快。 [localvideo]1472c2d4dc434d75629c53e42b78c157[/localvideo]  

  • 2025-01-18
  • 发表了主题帖: 【KW41Z开发板测评】②PWM输出呼吸灯

        承接上期的【KW41Z开发板测评】①开箱及搭建环境并点灯帖子,使用NXP官方的MCUXpresso IDE很容易导出体验官方的参考例程。     这期借助“frdmkw41z_driver_examples_tpm_simple_pwm”参考例程来实现呼吸灯效果。官方的例程是通过串口给开发板发“0”~“9”来手动调节占空比,从而使RGB灯的蓝色管脚输出固定值的占空比,调节灯的亮度。     根据RGB灯部分的原理图,可知控制RGB灯蓝色输出的信号脚为PTA18,复用为TPM2_CH0通道,这里简单分享一下。 根据数据手册可知,PTA18复用关系。 修改部分代码,工程源码关键部分展示如下: pin_mux.c #include "fsl_common.h" #include "fsl_port.h" #include "pin_mux.h" #define PIN6_IDX 6u /*!< Pin number for pin 6 in a port */ #define PIN7_IDX 7u /*!< Pin number for pin 7 in a port */ #define PIN18_IDX 18u /*!< Pin number for pin 18 in a port */ #define SOPT4_TPM2CH0SRC_TPM 0x00u /*!< TPM2 Channel 0 Input Capture Source Select: TPM2_CH0 signal */ #define SOPT5_LPUART0RXSRC_LPUART_RX 0x00u /*!< LPUART0 Receive Data Source Select: LPUART_RX pin */ /* * TEXT BELOW IS USED AS SETTING FOR THE PINS TOOL ***************************** BOARD_InitPins: - options: {coreID: singlecore, enableClock: 'true'} - pin_list: - {pin_num: '42', peripheral: LPUART0, signal: RX, pin_signal: TSI0_CH2/PTC6/LLWU_P14/XTAL_OUT_EN/I2C1_SCL/UART0_RX/TPM2_CH0/BSM_FRAME} - {pin_num: '43', peripheral: LPUART0, signal: TX, pin_signal: TSI0_CH3/PTC7/LLWU_P15/SPI0_PCS2/I2C1_SDA/UART0_TX/TPM2_CH1/BSM_DATA} - {pin_num: '6', peripheral: TPM2, signal: 'CH, 0', pin_signal: TSI0_CH12/PTA18/LLWU_P6/SPI1_SCK/TPM2_CH0} * BE CAREFUL MODIFYING THIS COMMENT - IT IS YAML SETTINGS FOR THE PINS TOOL *** */ /*FUNCTION********************************************************************** * * Function Name : BOARD_InitPins * Description : Configures pin routing and optionally pin electrical features. * *END**************************************************************************/ void BOARD_InitPins(void) { CLOCK_EnableClock(kCLOCK_PortA); /* Port A Clock Gate Control: Clock enabled */ CLOCK_EnableClock(kCLOCK_PortC); /* Port C Clock Gate Control: Clock enabled */ PORT_SetPinMux(PORTA, PIN18_IDX, kPORT_MuxAlt5); /* PORTA18 (pin 6) is configured as TPM2_CH0 */ PORT_SetPinMux(PORTC, PIN6_IDX, kPORT_MuxAlt4); /* PORTC6 (pin 42) is configured as UART0_RX */ PORT_SetPinMux(PORTC, PIN7_IDX, kPORT_MuxAlt4); /* PORTC7 (pin 43) is configured as UART0_TX */ SIM->SOPT4 = ((SIM->SOPT4 & (~(SIM_SOPT4_TPM2CH0SRC_MASK))) /* Mask bits to zero which are setting */ | SIM_SOPT4_TPM2CH0SRC(SOPT4_TPM2CH0SRC_TPM) /* TPM2 Channel 0 Input Capture Source Select: TPM2_CH0 signal */ ); SIM->SOPT5 = ((SIM->SOPT5 & (~(SIM_SOPT5_LPUART0RXSRC_MASK))) /* Mask bits to zero which are setting */ | SIM_SOPT5_LPUART0RXSRC(SOPT5_LPUART0RXSRC_LPUART_RX) /* LPUART0 Receive Data Source Select: LPUART_RX pin */ ); } tpm_simple_pwm.c #include "fsl_debug_console.h" #include "board.h" #include "fsl_tpm.h" #include "pin_mux.h" /******************************************************************************* * Definitions ******************************************************************************/ #define BOARD_TPM_BASEADDR TPM2 #define BOARD_TPM_CHANNEL 0U /* Interrupt to enable and flag to read; depends on the TPM channel used */ #define TPM_CHANNEL_INTERRUPT_ENABLE kTPM_Chnl0InterruptEnable #define TPM_CHANNEL_FLAG kTPM_Chnl0Flag /* Interrupt number and interrupt handler for the TPM instance used */ #define TPM_INTERRUPT_NUMBER TPM2_IRQn #define TPM_LED_HANDLER TPM2_IRQHandler /* Get source clock for TPM driver */ #define TPM_SOURCE_CLOCK CLOCK_GetFreq(kCLOCK_McgFllClk) /******************************************************************************* * Variables ******************************************************************************/ volatile bool brightnessUp = true; /* Indicate LED is brighter or dimmer */ volatile uint8_t updatedDutycycle = 10U; volatile uint8_t getCharValue = 0U; volatile uint32_t g_systickCounter; uint8_t dutyCycle = 0; uint8_t var = 0; /******************************************************************************* * Code ******************************************************************************/ void SysTick_Handler(void) { if (g_systickCounter != 0U) { g_systickCounter--; } } void SysTick_DelayTicks(uint32_t n) { g_systickCounter = n; while (g_systickCounter != 0U) { } } /*! * [url=home.php?mod=space&uid=159083]@brief[/url] Main function */ int main(void) { tpm_config_t tpmInfo; tpm_chnl_pwm_signal_param_t tpmParam; tpm_pwm_level_select_t pwmLevel = kTPM_LowTrue; /* Configure tpm params with frequency 24kHZ */ tpmParam.chnlNumber = (tpm_chnl_t)BOARD_TPM_CHANNEL; tpmParam.level = pwmLevel; tpmParam.dutyCyclePercent = updatedDutycycle; /* Board pin, clock, debug console init */ BOARD_InitPins(); BOARD_BootClockRUN(); BOARD_InitDebugConsole(); /* Select the clock source for the TPM counter as MCGPLLCLK */ CLOCK_SetTpmClock(1U); /* Set systick reload value to generate 1ms interrupt */ if (SysTick_Config(SystemCoreClock / 1000U)) { while (1) { } } TPM_GetDefaultConfig(&tpmInfo); /* Initialize TPM module */ TPM_Init(BOARD_TPM_BASEADDR, &tpmInfo); TPM_SetupPwm(BOARD_TPM_BASEADDR, &tpmParam, 1U, kTPM_CenterAlignedPwm, 24000U, TPM_SOURCE_CLOCK); TPM_StartTimer(BOARD_TPM_BASEADDR, kTPM_SystemClock); while (1) { if(var == 0) { dutyCycle+=10; } else if(var == 1) { dutyCycle-=10; } /* Disable channel output before updating the dutycycle */ TPM_UpdateChnlEdgeLevelSelect(BOARD_TPM_BASEADDR, (tpm_chnl_t)BOARD_TPM_CHANNEL, 0U); /* Update PWM duty cycle */ TPM_UpdatePwmDutycycle(BOARD_TPM_BASEADDR, (tpm_chnl_t)BOARD_TPM_CHANNEL, kTPM_CenterAlignedPwm, dutyCycle); /* Start channel output with updated dutycycle */ TPM_UpdateChnlEdgeLevelSelect(BOARD_TPM_BASEADDR, (tpm_chnl_t)BOARD_TPM_CHANNEL, pwmLevel); SysTick_DelayTicks(60U); if(dutyCycle > 90) var = 1; else if(dutyCycle < 10) var = 0; } } 然后Debug,将编译完的固件程序烧写到开发板中,运行程序,呈现呼吸道效果,见如下视频。 [localvideo]6a152fadf75f0a3e1a9a77b07faac7df[/localvideo]

  • 2025-01-17
  • 回复了主题帖: EEWorld 2024年度人物:感恩相伴,共赴新程,携手努力!

    2025,携手共进,风雨无阻,再创佳绩!

  • 2025-01-14
  • 发表了主题帖: 【KW41Z开发板测评】①开箱及搭建环境并点灯

    本帖最后由 yin_wu_qing 于 2025-1-14 22:00 编辑 一、概况        周日收到了年终回炉的“NXP FREEDOM DEVELOPMENT BOARD KW41Z”开发板,第一时间去到:MCUXpresso SDK 构建工具网站,登录NXP个人账号,进行SDK的构建、下载。通过面向Kinetis® KW41Z/31Z/21Z MCU的Freedom开发套件网址获取相关资料,FRDM-KW41Z板是一款支持无线多协议的开发板,主干框图如下: 二、开箱        收到的包裹中只用空气袋夹带着这块开发板,并没有microUSB数据线与BLE调试工具,不过这也并不影响后续的评测使用,空气袋包裹得还算比较严实,开发板正面干净,看上去有诸多跳线帽,还有外接天线的接口。 开发板背面有提供纽扣电池座,应用在低功耗场景,纽扣电池可让开发板进入到低功耗工作模式下持续供电。两旁的长长插针是正面的排座过孔延续。 将开发板上电检测一下,毕竟从包裹中拿出时,背面的插针有“东倒西歪”的。使用以前比较流行的MicroUSB数据线给板子上电,简单按键测试了下LED,功能正常。 三、搭建环境 从“MCUXpresso SDK构建工具”网页上获取关于KW41Z板的SDK时可知,该SDK导出只支持MCUXpresso IDE与IAR,并不支持MDK,因而笔者导出SDK时选择了MCUXpresso IDE,官方的工具导入工程也是非常方便。在IDE的左下栏中导入构建并下载好的SDK,这里建议不用解压,直接导入zip文件即可install。 接下来,傻瓜式选择“下一步”即可完成,然后import SDK中的工程示例。 这里笔者选择点灯例程 点击菜单栏下的“锤子”图标,进行工程的编译。 然后将编译好的程序下载到开发板中,由于该板集成了JLink调试器,只需要一根MicroUSB数据线即可完成下载、调试。 四、点灯效果 这里的例程,只是对GPIOC01管脚输出,即RGB灯的red红色点亮。程序解读,给GPIOC01输出低电平则红灯亮,输出高电平则红灯灭,效果如下: [localvideo]bf9892d6d8413ae5d7ee0cae38fc69e8[/localvideo]    

  • 2025-01-10
  • 回复了主题帖: 【回顾2024,展望2025】新年抢楼活动来啦!

    立一个新年Flag,身体健健康康,早睡早起,告别亚健康。

  • 2025-01-08
  • 加入了学习《Follow me 第二季第3期成果视频》,观看 成果展示

  • 回复了主题帖: 【测评入围名单(最后1批)】年终回炉:FPGA、AI、高性能MCU、书籍等65个测品邀你来~

    个人信息确认无误,确认可以完成评测计划。

学过的课程

统计信息

已有151人来访过

  • 芯积分:1665
  • 好友:--
  • 主题:60
  • 回复:171

留言

你需要登录后才可以留言 登录 | 注册


现在还没有留言