- 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个测品邀你来~
个人信息确认无误,确认可以完成评测计划。
- 2024-06-30
-
回复了主题帖:
免费申请 | 最新一代树莓派(Raspberry Pi 5)!
积极支持一下活动!好活动!
- 2024-05-18
-
发表了主题帖:
《python编程快速上手》第5篇:python之字典和结构化数据
“字典”是许多值的集合,但不像列表的索引,字典的索引可以使用许多不同的数据类型,不只是整数。字典的索引被称为“键”,键及其关联的值称为“键-值对”。字典中的项是不排序的,下面就字典与列表差异展开话题。
尽管字典是不排序的,但可以用任意值作为键,这一点让开发人员能够用强大的方式来组织数据。假定你希望程序保存你朋友的生日数据,就可以使用一个字典,用名字作为键,用生日作为值。在Mu编辑工具中,新建一个.py文件,并在编辑器窗口输入以下代码,完成编辑后运行、测试。
birthdays = {'Aloy':'Apr 5','Bob':'Dec 15','Carol':'Mar 18'}
while True:
print('Enter a name:(blank to quit)')
name = input()
if name == '':
break
if name in birthdays:
print(birthdays[name] + 'is the birthday of' + name)
else:
print('I do not have birthday information for '+ name)
print('What is their birthday?')
bday = input()
birthdays[name] = bday
print('Birthday database updated.')
运行后,测试效果如下:
由代码可知,创建了一个初始的字典,将它保存在birthdays。用if name in birthdays中的in关键字,可以查看输入的名字是否作为键存在于字典中,就像查看列表一样。如果该名字在字典中,那么就可以用birthdays[]来访问关联的值。如果不存在,则可以用同样的"birthdays[]=name"方式来赋值操作添加到字典中。
字典中有3个方法,分别对应与字典的键、值和键-值对,即keys()、values()和items()方法。这些方法返回的值并不是真正的列表,它们不能被修改,没有append()方法。利用keys()、values()和items()方法,循环分别可以迭代键、值和键-值对。items()方法返回的是dict_items值包含的是键和值的元组。
以上并不会返回得到真正的列表,如果想通过这些方法得到一个真正的列表,就要把类似列表的返回值传递给list()函数。
跟列表一样,in或not in操作符可以检查值是否存在与列表中,也可以利用这些操作符,检查某个键或值是否存在于字典中。
访问一个键的值之前,必须通过检查该键是否存在于字典中,才能合法访问,这显得很是麻烦,字典中有提供一个get()方法,有带两个参数,分别为要取得其值的键,以及当键不存在时返回的备用值。
在字典中常常需要将某个键设置一个默认值,当该键没有任何值时使用它需要重新设定,setdefault()方法提供了一种方法,可以在一行中完成这样的设置需求,该方法第一个参数是要检查的键,第二个参数是当该键不存在时要设置的值,如果该键确实存在,那么setdefault()方法就会返回键的值,效果如下交互环境。
setdefault()方法是一个很好的快捷方式,可以确保有一个键存在,下面的一个小程序可以诠释,轻松实现计算一个字符串中每个字符出现的次数。在Mu工具的编辑窗口输入以下代码,保存后运行即可输出结果。
message = 'It was a bright cold day in April, and the clocks were striking thirteen.'
count = {}
for character in message:
count.setdefault(character, 0)
count[character] = count[character] + 1
print(count)
运行输出的结果如下:
{'I': 1}
{'I': 1, 't': 1}
{'I': 1, 't': 1, ' ': 1}
{'I': 1, 't': 1, ' ': 1, 'w': 1}
{'I': 1, 't': 1, ' ': 1, 'w': 1, 'a': 1}
{'I': 1, 't': 1, ' ': 1, 'w': 1, 'a': 1, 's': 1}
{'I': 1, 't': 1, ' ': 2, 'w': 1, 'a': 1, 's': 1}
{'I': 1, 't': 1, ' ': 2, 'w': 1, 'a': 2, 's': 1}
{'I': 1, 't': 1, ' ': 3, 'w': 1, 'a': 2, 's': 1}
{'I': 1, 't': 1, ' ': 3, 'w': 1, 'a': 2, 's': 1, 'b': 1}
{'I': 1, 't': 1, ' ': 3, 'w': 1, 'a': 2, 's': 1, 'b': 1, 'r': 1}
{'I': 1, 't': 1, ' ': 3, 'w': 1, 'a': 2, 's': 1, 'b': 1, 'r': 1, 'i': 1}
{'I': 1, 't': 1, ' ': 3, 'w': 1, 'a': 2, 's': 1, 'b': 1, 'r': 1, 'i': 1, 'g': 1}
{'I': 1, 't': 1, ' ': 3, 'w': 1, 'a': 2, 's': 1, 'b': 1, 'r': 1, 'i': 1, 'g': 1, 'h': 1}
{'I': 1, 't': 2, ' ': 3, 'w': 1, 'a': 2, 's': 1, 'b': 1, 'r': 1, 'i': 1, 'g': 1, 'h': 1}
{'I': 1, 't': 2, ' ': 4, 'w': 1, 'a': 2, 's': 1, 'b': 1, 'r': 1, 'i': 1, 'g': 1, 'h': 1}
{'I': 1, 't': 2, ' ': 4, 'w': 1, 'a': 2, 's': 1, 'b': 1, 'r': 1, 'i': 1, 'g': 1, 'h': 1, 'c': 1}
{'I': 1, 't': 2, ' ': 4, 'w': 1, 'a': 2, 's': 1, 'b': 1, 'r': 1, 'i': 1, 'g': 1, 'h': 1, 'c': 1, 'o': 1}
{'I': 1, 't': 2, ' ': 4, 'w': 1, 'a': 2, 's': 1, 'b': 1, 'r': 1, 'i': 1, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 1}
{'I': 1, 't': 2, ' ': 4, 'w': 1, 'a': 2, 's': 1, 'b': 1, 'r': 1, 'i': 1, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 1, 'd': 1}
{'I': 1, 't': 2, ' ': 5, 'w': 1, 'a': 2, 's': 1, 'b': 1, 'r': 1, 'i': 1, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 1, 'd': 1}
{'I': 1, 't': 2, ' ': 5, 'w': 1, 'a': 2, 's': 1, 'b': 1, 'r': 1, 'i': 1, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 1, 'd': 2}
{'I': 1, 't': 2, ' ': 5, 'w': 1, 'a': 3, 's': 1, 'b': 1, 'r': 1, 'i': 1, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 1, 'd': 2}
{'I': 1, 't': 2, ' ': 5, 'w': 1, 'a': 3, 's': 1, 'b': 1, 'r': 1, 'i': 1, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 1, 'd': 2, 'y': 1}
{'I': 1, 't': 2, ' ': 6, 'w': 1, 'a': 3, 's': 1, 'b': 1, 'r': 1, 'i': 1, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 1, 'd': 2, 'y': 1}
{'I': 1, 't': 2, ' ': 6, 'w': 1, 'a': 3, 's': 1, 'b': 1, 'r': 1, 'i': 2, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 1, 'd': 2, 'y': 1}
{'I': 1, 't': 2, ' ': 6, 'w': 1, 'a': 3, 's': 1, 'b': 1, 'r': 1, 'i': 2, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 1, 'd': 2, 'y': 1, 'n': 1}
{'I': 1, 't': 2, ' ': 7, 'w': 1, 'a': 3, 's': 1, 'b': 1, 'r': 1, 'i': 2, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 1, 'd': 2, 'y': 1, 'n': 1}
{'I': 1, 't': 2, ' ': 7, 'w': 1, 'a': 3, 's': 1, 'b': 1, 'r': 1, 'i': 2, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 1, 'd': 2, 'y': 1, 'n': 1, 'A': 1}
{'I': 1, 't': 2, ' ': 7, 'w': 1, 'a': 3, 's': 1, 'b': 1, 'r': 1, 'i': 2, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 1, 'd': 2, 'y': 1, 'n': 1, 'A': 1, 'p': 1}
{'I': 1, 't': 2, ' ': 7, 'w': 1, 'a': 3, 's': 1, 'b': 1, 'r': 2, 'i': 2, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 1, 'd': 2, 'y': 1, 'n': 1, 'A': 1, 'p': 1}
{'I': 1, 't': 2, ' ': 7, 'w': 1, 'a': 3, 's': 1, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 1, 'd': 2, 'y': 1, 'n': 1, 'A': 1, 'p': 1}
{'I': 1, 't': 2, ' ': 7, 'w': 1, 'a': 3, 's': 1, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 2, 'd': 2, 'y': 1, 'n': 1, 'A': 1, 'p': 1}
{'I': 1, 't': 2, ' ': 7, 'w': 1, 'a': 3, 's': 1, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 2, 'd': 2, 'y': 1, 'n': 1, 'A': 1, 'p': 1, ',': 1}
{'I': 1, 't': 2, ' ': 8, 'w': 1, 'a': 3, 's': 1, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 2, 'd': 2, 'y': 1, 'n': 1, 'A': 1, 'p': 1, ',': 1}
{'I': 1, 't': 2, ' ': 8, 'w': 1, 'a': 4, 's': 1, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 2, 'd': 2, 'y': 1, 'n': 1, 'A': 1, 'p': 1, ',': 1}
{'I': 1, 't': 2, ' ': 8, 'w': 1, 'a': 4, 's': 1, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 2, 'd': 2, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1}
{'I': 1, 't': 2, ' ': 8, 'w': 1, 'a': 4, 's': 1, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 2, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1}
{'I': 1, 't': 2, ' ': 9, 'w': 1, 'a': 4, 's': 1, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 2, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1}
{'I': 1, 't': 3, ' ': 9, 'w': 1, 'a': 4, 's': 1, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 1, 'c': 1, 'o': 1, 'l': 2, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1}
{'I': 1, 't': 3, ' ': 9, 'w': 1, 'a': 4, 's': 1, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 2, 'c': 1, 'o': 1, 'l': 2, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1}
{'I': 1, 't': 3, ' ': 9, 'w': 1, 'a': 4, 's': 1, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 2, 'c': 1, 'o': 1, 'l': 2, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 1}
{'I': 1, 't': 3, ' ': 10, 'w': 1, 'a': 4, 's': 1, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 2, 'c': 1, 'o': 1, 'l': 2, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 1}
{'I': 1, 't': 3, ' ': 10, 'w': 1, 'a': 4, 's': 1, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 2, 'c': 2, 'o': 1, 'l': 2, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 1}
{'I': 1, 't': 3, ' ': 10, 'w': 1, 'a': 4, 's': 1, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 2, 'c': 2, 'o': 1, 'l': 3, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 1}
{'I': 1, 't': 3, ' ': 10, 'w': 1, 'a': 4, 's': 1, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 2, 'c': 2, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 1}
{'I': 1, 't': 3, ' ': 10, 'w': 1, 'a': 4, 's': 1, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 2, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 1}
{'I': 1, 't': 3, ' ': 10, 'w': 1, 'a': 4, 's': 1, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 2, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 1, 'k': 1}
{'I': 1, 't': 3, ' ': 10, 'w': 1, 'a': 4, 's': 2, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 2, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 1, 'k': 1}
{'I': 1, 't': 3, ' ': 11, 'w': 1, 'a': 4, 's': 2, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 2, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 1, 'k': 1}
{'I': 1, 't': 3, ' ': 11, 'w': 2, 'a': 4, 's': 2, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 2, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 1, 'k': 1}
{'I': 1, 't': 3, ' ': 11, 'w': 2, 'a': 4, 's': 2, 'b': 1, 'r': 2, 'i': 3, 'g': 1, 'h': 2, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 2, 'k': 1}
{'I': 1, 't': 3, ' ': 11, 'w': 2, 'a': 4, 's': 2, 'b': 1, 'r': 3, 'i': 3, 'g': 1, 'h': 2, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 2, 'k': 1}
{'I': 1, 't': 3, ' ': 11, 'w': 2, 'a': 4, 's': 2, 'b': 1, 'r': 3, 'i': 3, 'g': 1, 'h': 2, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 3, 'k': 1}
{'I': 1, 't': 3, ' ': 12, 'w': 2, 'a': 4, 's': 2, 'b': 1, 'r': 3, 'i': 3, 'g': 1, 'h': 2, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 3, 'k': 1}
{'I': 1, 't': 3, ' ': 12, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 3, 'i': 3, 'g': 1, 'h': 2, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 3, 'k': 1}
{'I': 1, 't': 4, ' ': 12, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 3, 'i': 3, 'g': 1, 'h': 2, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 3, 'k': 1}
{'I': 1, 't': 4, ' ': 12, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 4, 'i': 3, 'g': 1, 'h': 2, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 3, 'k': 1}
{'I': 1, 't': 4, ' ': 12, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 4, 'i': 4, 'g': 1, 'h': 2, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 3, 'k': 1}
{'I': 1, 't': 4, ' ': 12, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 4, 'i': 4, 'g': 1, 'h': 2, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 3, 'k': 2}
{'I': 1, 't': 4, ' ': 12, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 4, 'i': 5, 'g': 1, 'h': 2, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 2, 'A': 1, 'p': 1, ',': 1, 'e': 3, 'k': 2}
{'I': 1, 't': 4, ' ': 12, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 4, 'i': 5, 'g': 1, 'h': 2, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 3, 'A': 1, 'p': 1, ',': 1, 'e': 3, 'k': 2}
{'I': 1, 't': 4, ' ': 12, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 4, 'i': 5, 'g': 2, 'h': 2, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 3, 'A': 1, 'p': 1, ',': 1, 'e': 3, 'k': 2}
{'I': 1, 't': 4, ' ': 13, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 4, 'i': 5, 'g': 2, 'h': 2, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 3, 'A': 1, 'p': 1, ',': 1, 'e': 3, 'k': 2}
{'I': 1, 't': 5, ' ': 13, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 4, 'i': 5, 'g': 2, 'h': 2, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 3, 'A': 1, 'p': 1, ',': 1, 'e': 3, 'k': 2}
{'I': 1, 't': 5, ' ': 13, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 4, 'i': 5, 'g': 2, 'h': 3, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 3, 'A': 1, 'p': 1, ',': 1, 'e': 3, 'k': 2}
{'I': 1, 't': 5, ' ': 13, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 4, 'i': 6, 'g': 2, 'h': 3, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 3, 'A': 1, 'p': 1, ',': 1, 'e': 3, 'k': 2}
{'I': 1, 't': 5, ' ': 13, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 5, 'i': 6, 'g': 2, 'h': 3, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 3, 'A': 1, 'p': 1, ',': 1, 'e': 3, 'k': 2}
{'I': 1, 't': 6, ' ': 13, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 5, 'i': 6, 'g': 2, 'h': 3, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 3, 'A': 1, 'p': 1, ',': 1, 'e': 3, 'k': 2}
{'I': 1, 't': 6, ' ': 13, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 5, 'i': 6, 'g': 2, 'h': 3, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 3, 'A': 1, 'p': 1, ',': 1, 'e': 4, 'k': 2}
{'I': 1, 't': 6, ' ': 13, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 5, 'i': 6, 'g': 2, 'h': 3, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 3, 'A': 1, 'p': 1, ',': 1, 'e': 5, 'k': 2}
{'I': 1, 't': 6, ' ': 13, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 5, 'i': 6, 'g': 2, 'h': 3, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 4, 'A': 1, 'p': 1, ',': 1, 'e': 5, 'k': 2}
{'I': 1, 't': 6, ' ': 13, 'w': 2, 'a': 4, 's': 3, 'b': 1, 'r': 5, 'i': 6, 'g': 2, 'h': 3, 'c': 3, 'o': 2, 'l': 3, 'd': 3, 'y': 1, 'n': 4, 'A': 1, 'p': 1, ',': 1, 'e': 5, 'k': 2, '.': 1}
这样看起来比较费劲,可以引入pprint模块,这样就可以美观输出结果了,显得更直观、更优雅。
输出的结果如下:
{' ': 13,
',': 1,
'.': 1,
'A': 1,
'I': 1,
'a': 4,
'b': 1,
'c': 3,
'd': 3,
'e': 5,
'g': 2,
'h': 3,
'i': 6,
'k': 2,
'l': 3,
'n': 4,
'o': 2,
'p': 1,
'r': 5,
's': 3,
't': 6,
'w': 2,
'y': 1}
>>>
小结一下:通过本章节的学习,掌握了关于字典方面的相关知识,字典是非常有用的,因为开发者可以把一些项(键)映射到另一些项(值),不像列表只包含一系列有序的值。字典中的值是通过方括号访问的,像列表一样。字典不使用整数索引,而是用各种数据类型如整型、浮点型或元组作为键,通过将程序中的值组织成数据结构,开发者可以创建真实世界事物的模型。字典和结构化数据的学习,让我认识到Python这类解释性语言显得更宽泛化,不像C或C++,不拘束于数据类型,不用考虑占用字节长度,提供了另一种编程思想。此次分享告一段落,与大家共勉。
- 2024-05-12
-
发表了主题帖:
《python编程快速上手》第4篇:python之列表应用
Python中的“列表”是一个值,包含由多个值构成的序列。“列表值”是指列表本身,而不是指列表值之内的那些值。列表中的值也称为“表项”。变量名后面方括号内的整数被称为“索引”。列表中第一个值的索引是0,第二个值的索引是1,第三个值的索引是2,依次类推。
由上可知,如果使用的索引超出了列表值的个数,Python将给出IndexError错误信息,索引只能是整数,不能是浮点数。第一个索引表明使用哪个列表值,第二个索引表明该列表值中的值。比如spam[0][1]即第一个列表中的第二值,如果只使用一个索引,程序将输出该索引的完整列表值。
虽然索引从0开始并向上增长,但也可以用负整数作为索引。整数值-1指的是列表中的最后一个索引,-2指的是列表中倒数第二个索引。索引可以从列表中取得单个值一样,“切片”可以从列表中取得多个值,结果是一个新列表。切片用一对方括号来表示它的起止,像索引一样,它有两个由冒号分隔的整数。在一个切片中,第一个整数是切片开始处的索引,第二个整数是切片结束处的索引。切片向上增长,直至第二个索引的值,注但不包括它。作为快捷方法,可以省略切片中冒号两边的一个索引或者两个索引。省略第一个索引相当于使用索引0或从列表的开始处开始。省略第二个索引相当于使用列表的长度,意味着切片直接至列表末尾。
使用len()函数取得列表的长度
使用索引改变列表中的值,方法如下图所示:
列表可以连接和复制,就像字符串一样,使用del语句可以实现从列表中删除某一个值。
此书还介绍了使用列表的基本方法,有用于循环中,in和not in操作符可以确定一个值是否在列表中。多重赋值技巧让你在一行代码中,用列表中的值为多个变量赋值。列表可以与enumerate()函数,random.choice()和random.shuffle()函数一起使用。使用index()方法在列表中查找值,用append()方法和insert()方法在列表中添加值。
使用remove()方法从列表中删除值,使用sort()方法将列表中的值排序,使用reverse()方法反转列表中的值。
此次学习到此结束,受益匪浅,觉得Python的确很灵活,很人性化。
- 2024-05-03
-
发表了主题帖:
《python编程快速上手》第3篇:python之控制流与函数处理
Python的控制流语句的开始部分通常是“条件”,接下来是一个代码块。条件只是在控制流语句的上下文中更具体的名称,条件总是求值为一个布尔值:True或False。代码块的判定遵循以下3条规则:①、缩进增加时,代码块开始。②、代码块可以包含其他代码块。③、缩进减少为零,或与外面包围代码块对齐,代码块就此结束。
控制流语句与C语言大体相同,如if语句、else语句、elif语句、以及while循环语句、break语句、continue语句,for循环中引入了range()函数,则可控制代码块执行的次数,如需提前结束程序,调用sys.exit()函数。
Python程序中可以调用一组基本的函数,这称为“内置函数”,包括print()、input()和len()函数。Python也包括一组模块,称为“标准库”。每个模块都是一个Python程序,包含一组相关的函数,可以嵌入到程序之中,采用import关键字可以导入相关模块,与C语言中的include类似。
书籍循序渐进,有控制流代码块引出函数知识,由def语句开始讲解,这相当于C语音中的宏定义#define,书籍对“定义”“调用”“传递”“参数”和“变元”等术语进行辨析。“调用栈”是Python记住每个函数调用后在哪里返回执行的方式。调用栈不是存储在程序的变量中,而是由python在后台处理它。当程序调用一个函数时,python在调用栈的顶部创建一个“帧对象”。帧对象保存了最初函数调用的行号,使得python可以记住返回的位置。如果进行了另一个函数调用,python会将另一个帧对象放在调用栈中,且在前一个帧对象之上。当函数调用返回时,python从栈顶部删除一个帧对象,并将执行转移至保存在其中的行号。值得注意的是,帧对象始终是从栈顶部添加和删除的,而不是从其他任意位置。
Python中函数存在局域和全局作用域,在被调用函数内赋值的变元和变量。处于该函数的“局部作用域”中。在所有函数之外赋值单变量,处于“全局作用域”中。处于局部作用域中的变量,被称为“局部变量”。处于全局作用域中的变量,被称为“全局变量”。一个变量必属于其中一种,不能既是局部的又是全局的。
一个函数被调用时,就创建一个局部作用域。在这个函数内赋值的所用变量,存在于该局部作用域内。该函数返回时,这个局部作用域就被销毁了,这些变量就丢失了。下次调用这个函数时,局部变量不会记得该函数上次被调用时它们保存的值。作用域非常重要,理由如下:
一、全局作用域中的代码不能使用任何局部变量。
二、局部作用域中的代码可以访问全局变量。
三、一个函数的局部作用域中的代码,不能使用其他局部作用域中的变量。
四、在不同的作用域中,你可以用相同的名字命名不同的变量。
综上所述,函数是将代码逻辑分组的主要方式,函数中的变量存在于它们自己的局部作用域内,一个函数中的代码不能直接影响其他函数中变量的值。这限制了哪些代码才能改变变量的值,对于调式代码是很有帮助的。函数是很好的工具,可帮助编程人员组织代码,它们以参数的形式接收输入,以返回值的形式产生输出。它们内部的代码不会影响其他函数中的变量。
- 2024-05-02
-
发表了主题帖:
《python编程快速上手》第2篇:python基础语法篇
Python编程语言有许多语法结构、标准库函数和交互式开发环境功能。由于之前并没有接触Python脚本程序,但通过对此书的前几章内容学习,感觉与C语言有点类似,但也有许多地方不同之处。
Python数学操作符的优先级与数学中类似。**操作符表指数,*、/、//和%操作符,从左到右;+、- 操作符最后求值,同样的可以使用括号来改变通常的优先级。Python中的数据类型也有整型、浮点型、字符串类型连接和复制小结中,当在操作两个整型或浮点型值时,+是相加操作符,但在两个字符串之间,它则表式将字符串连接起来,成为“字符串连接”操作符。
Python语法中,“变量”就像计算机内存中的一个盒子,其中可以存放一个值。变量名命名也是有规则的,①、只能是一个词,不带空格。②、只能包含字母、数字和下划线“_”字符。③、不能以数字开头。变量名有区分大小写的。
接着引出了print()、input()、len()、str()、int()以及float()函数,可谓是受益匪浅,print()和input()函数处理简单的文本输出到屏幕和键盘输入;len()函数接收一个字符串,并求值为该字符串中字符的数目。str()、int()和float()函数将传入它们的值求值为字符串、整数或浮点数形式。
每个知识点,文中都有相关的程序举例,并且附带详细的程序剖析,可以让小白无门槛学习Python语法知识。书籍中还附带一本《Python学习效率手册》笔记本,8个星期的随学随记,“一个人走得慢,一群人学得稳”,经过基本语法的学习,觉得Python语言的编写格式有严格的讲究,包括首字符的缩进,没有C语言那么随意。
-
发表了主题帖:
《python编程快速上手》第1篇:开启扉页
本书的全名《Python编程快速上手---让繁琐工作自动化 第2版》,收到有段时间了,次书籍在异步社区有提供出售。书籍采用薄膜包装,防尘防水。书籍的正面、底面纸质华丽。
拆开新鲜薄膜,打开书籍的扉页,此书由中国工信出版集团,人民邮电出版社,字数618千字,2023年7月河北第15次印刷,本书分为两部分,第一部分介绍了基本的Python编程概念,第二部分介绍了一些不同的任务。前言部分作者申明了此书中的程序运行在Python3上,有一部分程序如果在Python2上也行不能正常运行。笔者早在之前就已经安装好python了,在计算机终端中输入:python -v,可知版本为3.11。
下载基于windows x64版本Mu编辑器软件,并傻瓜式安装,默认是安装到C盘个人本地路径下,并以python编程风格启动Mu。
此书集各大编程爱好者之精华,用户可通过扫码添加异步助手,获取本书籍的配套资源,如广大读者有发现错误,可到异步社区搜索此书名,进入本书页面,“提交勘误”,审核通过后可获得相应的奖励。前言篇到此结束,后续精彩继续。
- 2024-04-12
-
回复了主题帖:
读书入围名单:《Python编程快速上手 让繁琐工作自动化 第2版》
个人信息无误,确认可以完成阅读分享计划。