STM32 HAL库编程(3)—— PWM、SPI、NRF24L01通信


前言

本篇教程首先介绍PWM的概念和原理,利用stm32cubemx生成工程,并利用PWM控制LED的亮度;随后介绍另一种通信协议SPI;最后学习如何移植示例代码,实现利用NRF24L01进行通信

一、PWM的概念和产生原理

1. PWM的概念

PWM指脉冲宽度调制,是数字信号中重要的调制方式,包含频率占空比两个重要参数。对于数字信号,仅包含几个电压,例如stm32中只有0V和3.3V的低电平和高电平,无法产生0-3.3V之间的模拟电压。
通过PWM,改变高电平的时间,变相使得负载功率可调。例如stm32某一引脚产生PWM连接LED灯,高电平占空比越高,则LED灯越亮
因此PWM的一个作用是:控制一些器件以不同功率运行:控制LED灯的亮度程度,控制电机的转速等
在这里插入图片描述

2. PWM产生原理

在stm32中,PWM的原理是利用定时器比较器产生的:首先利用定时器产生某一个频率的周期信号(还记得定时器中断吗),这个就是PWM的周期;再利用比较器产生占空比,例如计数值是1000,那我比较值设置成400,那就会产生占空比位40%的PWM波

二、PWM工程

1. 新建工程

使用正点原子的板子,芯片为STM32F103RCT6,依次按照芯片选择、设置debug、配置时钟、最后工作步骤新建一个工程。

2. 设置PWM

前面说到,PWM是利用STM32中的定时器产生的,对于某些高级的定时器,它具有4个通道,这些通道可以映射到一些引脚上,从而在这些引脚上产生PWM信号。
查看手册,正点原子的LED0的引脚为PA8,正好为定时器1的通道1上。
打开定时器1的时钟,并设置通道1为PWM生成,并合理设置预分频和计数值,使频率为1Hz,并设置比较值为计数值的一半,从而产生占空比为**50%**的PWM信号。
在这里插入图片描述

3. 代码介绍

生成的代码,查看tim.c文件,可以看到配置的预分频和计数值,并且比较值为计数值的一半。
再复习下定时器频率计算方法:72MHz/预分频/计数值。
在这里插入图片描述

4. 代码编写

只需再代码中打开定时器的PWM即可。
在这里插入图片描述

HAL_TIM_PWM_Start(&htim1, TIM_CHANNEL_1);

5. 实验现象

烧录之后,观察LED的闪烁情况,可以看到LED每隔1s闪烁依次,其中亮的时间为500ms。

6. 代码修改1

由于没有示波器,通过LED的亮度来观察占空比影响。修改占空比为10%和90%,观察LED的亮度变化。
10%时比较值为100-1,90%时比较值为900-1。可以在STM32CUBEMX中修改配置,也可以直接在tim.c中修改,注意在tim.c中修改后,下次重新生成会变回原来的。

7. 代码修改2

上述可以观察到LED亮的时间有所不同,但没有达到改变LED亮度的目的,这是由于PWM的频率过低导致的。
提高PWM的频率,使得LED的闪烁频率超过人眼能够察觉的频率,即可达到改变LED亮度的目的。
合理改变定时器的预分频和计数值,并改变比较值,观察LED亮度的变化。

  1. 预分频和计数值分别为72-1和100-1,此时定时器的频率为10KHz;
  2. 比较值设置为10-1,占空比为10%,比较值设置为90-1,占空比为90%。

8. 代码修改3

通过上述的代码,已经知道设置定时器的预分频和计数值,可以改变PWM的频率;设置比较值,可以改变PWM的占空比。
为修改比较值,我们可以直接操作定时器的CCR寄存器,改变比较值。如以下代码为修改定时器1的通道1的比较值为10-1:
TIM1 -> CCR1 = 10-1;
也可以利用函数进行修改,HAL库中修改寄存器的函数有个特点,就是函数前会有两个下划线,上述操作的对应函数为:
__HAL_TIM_SET_COMPARE(&htim1, TIM_CHANNEL_1, 10-1);
修改while中代码,让LED的亮度发生自动发生变化:
在这里插入图片描述

9. 总结

PWM的作用不仅如此,其优秀的频率和占空比控制,在DAC和通信仍发挥着重要作用。但改变负载功率仍然是最重要的一个应用。比如在无人船中,当需要船向左旋转,只需要合理降低左电机的占空比、增加右电机的占空比,就可以让船向左旋转。

二、SPI通信

1. SPI概念

  1. 基本概念:SPI是单片机另一重要的通信方式和协议(上次我们讲了串口),它是同步通信,因此有同步时钟,区别于异步串口。
  2. SPI通信线:需要3根线,分别为SCK(时钟线)、MOSI(主出从如线,M为主机,S为从机,OI为输出输入的意思)和MISO(主入从出线)。
  3. 理解:从上面可以知道,SPI通信需要首先确定主机,一半设置设置STM32为主机,传感器为从机。因此STM32控制时钟脉冲的产生,并从MOSI输出数据给从机,从MISO从从机中读取数据。
  4. 另外SPI通信过程中,输出数据和读取数据的过程的同步的,也就是说,输出一个bit,就会输入一个bit。想要输入一个bit,就得输出1bit。一个脉冲,将会产生1bit的数据交换。

2. SPI多设备通信

SPI可以与一个设备或多个设备通信,为确定与哪一个进行通信,需设置相应的ES线,即片选线,当某一设备的片选信号被使能后,该设备将与主机进行通信。如下图,主机与一个或多个设备连接,设置对应的CS线(图中显示为SS)即可确定与哪一个设备通信。
在这里插入图片描述

三、NRF24L01模块

1. NRF24L01模块介绍

NRF24L01是一款工作在2.4GHz的无线通信模块,可以实现一对一、一对多、多对一的通信;并且具有自动重发功能,和自动ACK,来判断信息是否被接收到。
在这里插入图片描述

2. NRF24L01模块引脚

VCC和GND,还有6个引脚,其中SCK、MOSI和MISO为SPI通信的三个引脚,CSN为片选引脚(N表示有效信号为低电平),CE为使能引脚(进行数据发送或接收时设置),以及可配置中断引脚IRQ(当数据发送完成、或有数据接收到时,将会在IRQ引脚产生脉冲。单片机连接该引脚并配置中断模式,当数据发送或接收时,就可以跳到中断函数中处理

四、NRF24L01工程

使用小的核心板作为发送端,正点原子的板子作为接收端。正点原子的板子,直接烧录实验24的代码。
以下将新建工程,配置SPI,代码移植,实现小的开发板利用NRF24L01模块进行数据发送

1. 新建工程

使用STM32CUBEMX新建工程,使用小的核心板,芯片为STM32F103C8T6。并配置PC13引脚为LED,测试LED闪烁代码。
在这里插入图片描述

2. 配置SPI

由于NRF24L01的最高速率为10MHz,需要设置SPI的分配,使之不超过10MHz。
在这里插入图片描述

3. 添加其他引脚,并修改名称

继续设置NRF24L01的其他引脚,其中IRQ设置为输入模式CE和CSN设置为输出模式,并且均为高电平。修改各个引脚的名称,引脚的配置如下:

  1. NRF_CE -> PB1,输出模式,高电平
  2. NRF_CSN -> PB0,输出模式,高电平
  3. NRF_SCK -> PA5
  4. NRF_MOSI -> PA7
  5. NRF_MISO -> PA6
  6. NRF_IRQ -> PA4,输入模式,上拉
    在这里插入图片描述

4. 代码介绍

在这里插入图片描述

五、代码移植

1. 主要内容

代码移植,即将已有的代码复制复制过去,并修改一些内容,使之可以在新的板子上运行。
对于代码移植,主要需要考虑到以下几点:

  1. 引脚。引脚是最重要的部分,在新的板子上, 引脚一般不同,设置标签就是为了方便引脚的替换,引脚不同,但标签相同,就可以直接重新设置标签对应的引脚。
  2. 数据类型。虽然单片机的数据类型就几类,无符号、有符号的,8位、16位、32位的,但名字会有不同。例如hal库中无符号8位的数据类型位uint8_t,而正点原子使用了u8来表示,可通过类型声明typedef uint8_t u8;,让u8也表示uint8_t。
  3. 基本函数。包含初始化函数基本函数。初始化函数是对引脚、外设的初始化,我们已经使用了STM32CUBEMX进行引脚和外设配置了,所以这部分可以直接删除或注释。基本函数是指引脚读写、外设读写等函数,这是构成其他函数的基本,一般来说,把基本函数移植好了,其他函数就都可以用了。

2. 正点原子代码移植注意事项

对于正点原子的代码,除上述三点在移植中需要注意,还要把sys.h中的一些引脚读写内容进行移植。如图为sys.h中的主要内容,除前三行和最后一行不用,其他全部都要复制过去,就复制到新工程的main.h文件中。
在这里插入图片描述

3. 移植sys.h

打开正点原子 hal库源代码 实验24的工程,打开sys.c,并从中跳到sys.h文件中,除前三行和最后一行,其他全部复制到新工程的main.h文件中的合适位置。
在这里插入图片描述在这里插入图片描述

4. 移植24l01.c和24l01.h

移植好了sys.h代码,接下来就是开始正题。对于24l01.c和24l01.h,可以直接复制粘贴这两个文件到新工程的文件夹下;也可以在新工程中新建文件,复制代码过去。两个方法是一样的,我们使用第二个方法。

  1. 新建文件,复制粘贴24l01.c的所有代码。 在这里插入图片描述
  2. 保存文件,首先新建一个文件夹USER_CODE(其他名字也可以),将文件命名为24l01.c并保存到这个文件夹中。 在这里插入图片描述
  3. 复制粘贴保存24l01.h文件,以同样的方式处理24l01.h文件。
  4. 添加24l01.c文件到工程中:首先新建Group,并重新命名(重命名为先鼠标左击,过一小会鼠标左击,即可重命名;也可再上方的图标进行重命名);随后双击新建的Group,添加24l01.c文件。
    在这里插入图片描述
    在这里插入图片描述
  5. 添加.h文件。在这里插入图片描述
  6. 编译,发现都是报错,需要对.c和.h文件进行以下处理: 在这里插入图片描述在这里插入图片描述
    在这里插入图片描述
  7. 再次编译,发现还有两个错误,是SPI1_SetSpeed()SPI1_ReadWriteByte()两个函数未定义,这是基础函数,我们继续移植。

5. 移植基本函数

前面提到两个基本函数没有移植,其位于正点原子代码中的spi.c文件中,进行以下操作,将代码复制到新工程的spi.c中,并在spi.h中声明函数在这里插入图片描述
在这里插入图片描述

六、代码编写

在main函数中编写代码,实现不断发送数据。根据之前的引脚配置,连接NRF模块,烧录进行测试下吧!
在这里插入图片描述

u8 tmp_buf[33];								// 待发送数据
u8 i;
for(i=0; i<32; i++)
{
	tmp_buf[i] = 'a';						// 数据都为a
}
tmp_buf[32] = 0;							// 数据最后一位需为0

NRF24L01_Init();    		    	//初始化NRF24L01
while(NRF24L01_Check())				//检查,没有则快闪LED
{
	HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
	HAL_Delay(100);
}
NRF24L01_TX_Mode();					// 设置为输出模式
// 以下为不断发送数据
if(NRF24L01_TxPacket(tmp_buf)==TX_OK)
{
	// 如果发送成功并被接收到,则LED保持常亮
	HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, 0);
}else
{
	// 否则LED闪烁,以1s一次闪烁的频率
	HAL_GPIO_TogglePin(LED_GPIO_Port, LED_Pin);
}
HAL_Delay(500);
  • 17
    点赞
  • 71
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值