之前的博客《STM32CubeMX开发环境搭建及示例》已经搭建好了开发环境,但是在开发的过程中总是忘记STM32CubeMX是如何配置工程的,所以这里随手记录一下,本篇博客会随着自己的学习不定时更新。
STM32CubeMX工程配置——以STM32F103C8T6为例


我之所以这么选择,是因为我在High Speed Clock这个接口上外接了一个8Mhz的晶振



copy all used libraries into the projectfolder:复制所有库文件(不管工程需要用到还是没用到)到生成的工程目录中,此做法可以使在不使用Cubemx或者电脑没有安装cubemx,依然可以按照标准库的编程习惯调用HAL库函数进行程序编写。
Copy only the necessary library files: 只复制必要的库文件。这个相比上一个减少了很多文件。比如你没有使用CAN、SPI…等外设,就不会拷贝相关库文件到你工程下。
Add necessary library files as reference in the toolchain projectconfiguration file:在工具链项目配置文件中添加必要的库文件作为参考。这里没有复制HAL库文件,只添加了必要文件(如main.c)。相比上面,没有Drivers相关文件。
Generate peripheral initialization as a pair of’.c/.h’ files perperipheral:每个外设生成独立的.C .H文件,方便独立管理。不勾:所有初始化代码都生成在main.c勾选:初始化代码生成在对应的外设文件。 如UART初始化代码生成在uart.c中。
Backup previously generated files whenre-generating:在重新生成时备份以前生成的文件。重新生成代码时,会在相关目录中生成一个Backup文件夹,将之前源文件拷贝到其中。
keep user code when re-generating:重新生成代码时,保留用户代码(前提是代码写在规定的位置。也就是生成工程文件中的BEGIN和END之间。否则同样会删除。后面会根据生成的工程进行说明)
delete previously generated files when not re-generated:删除以前生成但现在没有选择生成的文件比如:之前生成了led.c,现在重新配置没有led.c,则会删除之前的led.c文件。(此功能根据自身要求进行取舍)


HAL_UART_Transmit():串口发送数据,使用超时管理机制
HAL_UART_Receive():串口接收数据,使用超时管理机制
HAL_UART_Transmit_IT():串口中断模式发送
HAL_UART_Receive_IT():串口中断模式接收
HAL_UART_Transmit_DMA():串口DMA模式发送
HAL_UART_Transmit_DMA():串口DMA模式接收
串口发送数据:
HAL_UART_Transmit(UART_HandleTypeDef *huart, uint8_t *pData, uint16_t Size, uint32_t Timeout)
功能:
串口发送指定长度的数据。如果超时没发送完成,则不再发送,返回超时标志(HAL_TIMEOUT)。
参数:
/* USER CODE BEGIN 1 */
#if 1
#include <stdio.h>
int fputc(int ch, FILE *stream)
{
/* 堵塞判断串口是否发送完成 */
while((USART1->SR & 0X40) == 0);
/* 串口发送完成,将该字符发送 */
USART1->DR = (uint8_t) ch;
return ch;
}
#endif
/* USER CODE END 1 */

HAL_ADCEx_Calibration_Start(&hadc1);//开启ADC校准
HAL_ADCEx_Calibration_Start(&hadc2);
//=============================================================================
//函数名称:Adc_Battery()
//功能概要:读取电池电压值
//参数说明:无
//函数返回:无
//=============================================================================
void Adc_Battery(void)
{
HAL_ADC_Start(&hadc2);//启动ADC装换
HAL_ADC_PollForConversion(&hadc2, 5);//等待转换完成,第二个参数表示超时时间,单位ms.
if(HAL_IS_BIT_SET(HAL_ADC_GetState(&hadc2), HAL_ADC_STATE_REG_EOC))
{
Battery = HAL_ADC_GetValue(&hadc2);//读取ADC转换数据,数据为12位
Battery = (float)Battery*(3.300/4096)*1000;
Battery = Battery*4.0;
}
}


DMA Request : DMA传输的对应外设
注意: 如果你是在DMA设置界面添加DMA 而没有开启对应外设的话 ,默认为MENTOMEN
Channel:DMA传输通道设置
DMA1:DMA1 Channel 0~DMA1 Channel 7
DMA2:DMA2 Channel 1~DMA2 Channel 5
Dirction : DMA传输方向
四种传输方向:
外设到内存 Peripheral To Memory
内存到外设 Memory To Peripheral
内存到内存 Memory To Memory
外设到外设 Peripheral To Peripheral
Priority: 传输速度
最高优先级 Very Hight
高优先级 Hight
中等优先级 Medium
低优先级;Low
DMA传输模式
Normal:正常模式 当一次DMA数据传输完后,停止DMA传送 ,也就是只传输一次
Circular: 循环模式 传输完成后又重新开始继续传输,不断循环永不停止
Increment Address:地址指针递增(上方有介绍)。
左侧Src Memory 表示外设地址寄存器 功能:设置传输数据的时候外设地址是不变还是递增。如果设置 为递增,那么下一次传输的时候地址加Data Width个字节
右侧Dst Memory 表示内存地址寄存器 功能:设置传输数据时候内存地址是否递增。如果设置 为递增,那么下一次传输的时候地址加 Data Width个字节
//=============================================================================
//函数名称:DMA_Adc_collect()
//功能概要:读取DMA_AD值
//参数说明:无
//函数返回:无
//=============================================================================
void DMA_Adc_collect(void)
{
uint8_t r,i,m;
for(r=0; r<12; r++)//行
{
HAL_GPIO_WritePin(GPIOA, R_A_Pin, Row_A[0]);
HAL_GPIO_WritePin(GPIOA, R_B_Pin, Row_B[0]);
HAL_GPIO_WritePin(GPIOA, R_C_Pin, Row_C[0]);
HAL_GPIO_WritePin(GPIOA, R_D_Pin, Row_D[0]);
delay_us(50);
HAL_ADC_Start_DMA(&hadc1, (uint32_t*)&ADC_ConvertedValue, 4);
delay_us(50);
for(i=0;i<4;i++)
{
m = Row_list[i];//列顺序
VoltageS[r][m]=(uint16_t)((float)ADC_ConvertedValue[i]/4096*3.300*1000)%10000;
}
}
}

这里设置I2C传输速率为400000,是因为这里是针对MPU6050设置的,6050可支持400Khz的IIC通信接口。
因为我们的硬件IIC 芯片一般都是主设备,也就是一般情况设置主模式即可
Master features 主模式特性
I2C Speed Mode: IIC模式设置 快速模式和标准模式。实际上也就是速率的选择。
I2C Clock Speed:I2C传输速率,默认为100KHz
Slave features 从模式特性
Clock No Stretch Mode: 时钟没有扩展模式
IIC时钟拉伸(Clock stretching) clock
stretching通过将SCL线拉低来暂停一个传输.直到释放SCL线为高电平,传输才继续进行.clock
stretching是可选的,实际上大多数从设备不包括SCL驱动,所以它们不能stretch时钟.Primary Address Length selection: 从设备地址长度 设置从设备的地址是7bit还是10bit大部分为7bit
Dual Address Acknowledged: 双地址确认
Primary slave address: 从设备初始地址
以下内容主要参考《STM32CubeMX | 36 - 使用CAN总线进行双板通信(TJA1050)》。
配置CAN控制只需配置波特率,一般为500KHz,最高1MHz,其它保持默认即可。
CAN总线的波特率比较特别,串口协议的波特率只支持一个确定值,而CAN总线的波特率支持一个较宽的范围,这也使得CAN总线的抗噪声性能大大增强。
CAN总线的波特率计算方式如下:
① 确定CAN外设连接的外设总线时钟PCLK1
此处CAN1连接到APB1外设总线上,在配置HCLK=72Mhz的基础上,PCLK=36Mhz。

② 确定分频系数
此处将PCLK1进行7分频,为 36Mhz / 6 = 6Mhz,所以设置CAN1外设的分频系数为6:

③ 配置位段时序
CAN协议的每一个数据位都分为许多时间段,如图:

同步段(SYNC_SEG):位变化应该在此时间段内发生,只有一个时间片的固定长度(1 x tq);
位段1(BS1):定义采样点的位置,其持续长度可以在 1 到 16 个Tq之间调整;
位段2(BS2):定义发送点的位置,其持续长度可以在1 到 8 个Tq之间调整;
同步跳转宽度(SJW):定义位段加长或缩短的上限,它可以在 1 到 4 个Tq之间调整;
目标波特率是500khz,设:
B
S
1
+
B
S
2
+
S
J
W
=
T
BS1+BS2+SJW=T
BS1+BS2+SJW=T
根据:
6
M
h
z
/
T
=
6000
k
h
z
/
T
=
500
k
h
z
6Mhz/T=6000khz/T=500khz
6Mhz/T=6000khz/T=500khz
计算出:
T
=
12
T=12
T=12
最后在BS1、BS2、SJW的每个范围内,调整出和为12即可,配置如下:


①编写CAN过滤器配置函数
在 CAN 协议中,发送节点将报文广播给所有接收器。而接收节点会根据报文标识符的值来确定节点是否需要该消息,为了简化软件的工作, STM32 的 CAN 外设接收报文前会先使用过滤器检查,只接收需要的报文到 FIFO 中。
STM32的CAN控制器一共有 28 个过滤器,CAN1 和 CAN2 共用这些过滤器。
CAN过滤器结构体定义在stm32f4xx_hal_can.h文件中,在main.c中编写CAN过滤器配置函数(不进行任何过滤):
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* CAN过滤器配置函数 */
static void CANFilter_Config(void)
{
CAN_FilterTypeDef sFilterConfig;
sFilterConfig.FilterBank = 0; //CAN过滤器编号,范围0-27
sFilterConfig.FilterMode = CAN_FILTERMODE_IDMASK; //CAN过滤器模式,掩码模式或列表模式
sFilterConfig.FilterScale = CAN_FILTERSCALE_32BIT; //CAN过滤器尺度,16位或32位
sFilterConfig.FilterIdHigh = 0x000 << 5; //32位下,存储要过滤ID的高16位
sFilterConfig.FilterIdLow = 0x0000; //32位下,存储要过滤ID的低16位
sFilterConfig.FilterMaskIdHigh = 0x0000; //掩码模式下,存储的是掩码
sFilterConfig.FilterMaskIdLow = 0x0000;
sFilterConfig.FilterFIFOAssignment = 0; //报文通过过滤器的匹配后,存储到哪个FIFO
sFilterConfig.FilterActivation = ENABLE; //激活过滤器
sFilterConfig.SlaveStartFilterBank = 0;
if (HAL_CAN_ConfigFilter(&hcan1, &sFilterConfig) != HAL_OK) {
Error_Handler();
}
}
/* USER CODE END 0 */
其中,不同配置模式下四个数据成员内容对应的含义:

② 定义接收和发送消息变量
在main.c文件中定义CAN接收和发送消息变量:
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
static CAN_TxHeaderTypeDef TxMessage; //CAN发送的消息的消息头
static CAN_RxHeaderTypeDef RxMessage; //CAN接收的消息的消息头
/* USER CODE END PV */
③ 编写CAN接收中断处理函数
在main.c文件的最后编写CAN接收中断处理函数:
/* USER CODE BEGIN 4 */
void HAL_CAN_RxFifo0MsgPendingCallback(CAN_HandleTypeDef *hcan)
{
uint8_t data[8];
HAL_StatusTypeDef status;
if (hcan == &hcan1) {
status = HAL_CAN_GetRxMessage(hcan, CAN_RX_FIFO0, &RxMessage, data);
if (HAL_OK == status){
printf("--->Data Receieve!\r\n");
printf("RxMessage.StdId is %#x\r\n", RxMessage.StdId);
printf("data[0] is 0x%02x\r\n", data[0]);
printf("data[1] is 0x%02x\r\n", data[1]);
printf("data[2] is 0x%02x\r\n", data[2]);
printf("data[3] is 0x%02x\r\n", data[3]);
printf("<---\r\n");
}
}
}
/* USER CODE END 4 */
④ 编写CAN发送测试数据函数
/* CAN 发送数据测试函数 */
void CAN1_Send_Test()
{
uint8_t data[4] = {0x01, 0x02, 0x03, 0x04};
TxMessage.IDE = CAN_ID_STD; //设置ID类型
TxMessage.StdId = 0x222; //设置ID号
TxMessage.RTR = CAN_RTR_DATA; //设置传送数据帧
TxMessage.DLC = 4; //设置数据长度
if (HAL_CAN_AddTxMessage(&hcan1, &TxMessage, data, (uint32_t*)CAN_TX_MAILBOX0) != HAL_OK) {
Error_Handler();
}
}
⑤ 编写初始化函数
修改main函数,在其中配置CAN滤波器、启动CAN控制器、使能CAN控制器接收中断:
/* USER CODE BEGIN 2 */
/* 1. CAN Filter Config */
CANFilter_Config();
/* 2. CAN Start */
if (HAL_CAN_Start(&hcan1) != HAL_OK) {
Error_Handler();
}
/* 3. Enable CAN RX Interrupt */
if (HAL_CAN_ActivateNotification(&hcan1, CAN_IT_RX_FIFO0_MSG_PENDING) != HAL_OK) {
Error_Handler();
}
/* USER CODE END 2 */
首先查看时钟树:

定时器的时钟来自于内部的PLL分频->AHB->APB1或2(到底是APB1还是2,需要查手册,或者源码中的宏,如下图可见,2/3/4是在APB1上的,如下图可见,1是在APB2上的)


定时器溢出时间的计算:
T
=
(
(
p
e
r
i
o
d
+
1
)
∗
(
p
s
c
+
1
)
)
/
(
T
I
M
_
C
L
K
_
M
h
z
/
T
I
M
_
C
l
o
c
k
D
i
v
i
s
i
o
n
)
T=((period+1)*(psc+1))/(TIM\_CLK\_Mhz / TIM\_ClockDivision)
T=((period+1)∗(psc+1))/(TIM_CLK_Mhz/TIM_ClockDivision)
period:周期寄存器TIMx->Arr的值,
psc:预分频寄存器TIMx->PSC的值,
TIM_CLK_Mhz:定时器的时钟源频率
TIM_ClockDivision:再分频系数

T
=
(
7200
∗
5000
)
/
(
72000000
∗
1
)
=
0.5
s
T = (7200*5000)/(72000000*1)=0.5s
T=(7200∗5000)/(72000000∗1)=0.5s
至此配置已全部完成。
不过要想在程序里用起来,还得再写几行代码:
在main中添加一行代码:启动定时器+定时器中断
HAL_TIM_Base_Start_IT(&htim1);
文章目录1.开发板选择*用到的资源2.串口通信(个人理解)3.代码分析(注释比较详细)1.主函数2.串口1配置3.串口2配置以及中断函数4.注意问题5.源码链接1.开发板选择我用的是STM32F103RCT6的板子,不过代码大概在F103系列的板子上都可以运行,我试过在野火103的霸道板上也可以,主要看一下串口对应的引脚一不一样就行了,不一样的就更改一下。*用到的资源keil5软件这里用到了两个串口资源,采集数据一个,串口通信一个,板子对应引脚如下:串口1,TX:PA9,RX:PA10串口2,TX:PA2,RX:PA32.串口通信(个人理解)我就从串口采集传感器数据这个过程说一下我自己的理解,
下载微PE工具箱进入官网下载微PE工具箱-下载 安装好后,打开微PE工具箱客户端,选择安装PE到U盘 PE壁纸可选择自己喜欢的壁纸,勾选上包含DOS工具箱,个性化盘符图标 下载原版系统进入网站下载镜像NEXT,ITELLYOU如果没有账号,注册一下就好进入选择开始使用选择win10 这里我们选择消费者版,用迅雷把BT种子下载下来 下面的两个盘符,是PE工具箱安装进U盘后,分成的盘符,注意EFI的盘符,这里面不能删东西,也不能添东西,另一个盘符可以当做正常的U盘空间使用,我们现在需要把下载下来的景象文件复制到正常的U盘空间中去 这个时候我们的系统U盘就只做好了 安装系统我们将U盘插入电脑,开机,
LL库和HAL库简介LL:Low-Layer,底层库HAL:HardwareAbstractionLayer,硬件抽象层库LL库和hal库对比,很精简,这实际上是一个精简的库。LL库的配置选择如下:在STM32CUBEMX中,点击菜单的“ProjectManager”–>“AdvancedSettings”,在下面的界面中选择“AdvancedSettings”,然后在每个模块后面选择使用的库总结:1、如果使用的MCU是小容量的,那么STM32CubeLL将是最佳选择;2、如果结合可移植性和优化,使用STM32CubeHAL并使用特定的优化实现替换一些调用,可保持最大的可移植性。另外HAL和L
目录一、ESP32简单介绍二、ESP32Wi-Fi模块介绍三、ESP32Wi-Fi编程模型四、ESP32Wi-Fi事件处理流程 五、ESP32Wi-Fi开发环境六、ESP32Wi-Fi具体代码七、ESP32Wi-Fi代码解读6.1主程序app_main7.2自定义代码wifi_init_sta()八、ESP32Wi-Fi连接验证8.1测试方法8.2服务器模拟工具sscom58.3测试代码8.4测试结果前言为了开发一款亚马逊物联网产品,开始入手ESP32模块。为了能够记录自己的学习过程,特记录如下操作过程。一、ESP32简单介绍ESP32是一套Wi-Fi(2.4GHz)和蓝牙(4.2)双模解决方
有道无术,术尚可求,有术无道,止于术。本系列SpringBoot版本3.0.4本系列SpringSecurity版本6.0.2本系列SpringAuthorizationServer版本1.0.2源码地址:https://gitee.com/pearl-organization/study-spring-security-demo文章目录前言1.OAuth2AuthorizationServerMetadataEndpointFilter2.OAuth2AuthorizationEndpointFilter3.OidcProviderConfigurationEndpointFilter4.N
在我的代码中,我需要使用各种算法(包括CRC32)对文件进行哈希处理。因为我还在Digest系列中使用其他加密哈希函数,所以我认为为它们维护一个一致的接口(interface)会很好。为了记录,我确实找到了digest-crc,一颗完全符合我要求的gem。问题是,Zlib是标准库的一部分,并且有一个我想重用的CRC32工作实现。此外,它是用C编写的,因此它应该提供与digest-crc相关的卓越性能,后者是纯ruby实现。实现Digest::CRC32一开始看起来非常简单:%w(digestzlib).each{|f|requiref}classDigest::CRC32一切正常:
我正在尝试在我的机器上安装win32-apigem,但在构建native扩展时我遇到了一些问题:$geminstallwin32-api--no-ri--rdocTemporarilyenhancingPATHtoincludeDevKit...Buildingnativeextensions.Thiscouldtakeawhile...C:\Programs\dev_kit\bin\make.exe:***Couldn'treservespaceforcygwin'sheap,Win32error0ERROR:Errorinstallingwin32-api:ERROR:Failed
我在Windows上运行ruby1.9.2并试图移植在Ruby1.8中工作的代码。该代码使用以前运行良好的Open4.popen4。对于1.9.2,我做了以下事情:通过geminstallPOpen4安装了POpen4需要POpen4通过require'popen4'尝试像这样使用POpen4:Open4.popen4("cmd"){|io_in,io_out,io_er|...}当我这样做时,我得到了错误:nosuchfiletoload--win32/open3如果我尝试安装win32-open3(geminstallwin32-open3),我会收到错误消息:win32-op
DellInspiron5488加内存32G 原装内置内存仅仅8G,目前看,真的太小了! 1.内存型号Dell5488内存型号:DDR42666。笔记本有两个内存插槽,原装占了一个,还能扩展一个。 2.买内存如果买Dell原装笔记本内存,8G就得500块左右。 我咨询了一下,三星的笔记本内存,可以兼容。16G,299块(2023年2月23日,京东价) Dell5488内存组合,最多只能插两根16G内存。 我于是买了两根三星16G内存。装上,很爽😄 跑国产系统统信UOS,再也看不到用交换区了,32G内存,爽!
本文代码使用HAL库。文章目录前言一、MCP4017的重要特性二、MCP4017计算RBW阻值三、MCP4017地址四、MCP4017读写函数五、CubeMX创建工程(利用ADC测量MCP4017电压)、对应代码:总结前言一、MCP4017的重要特性蓝桥杯板子上的是MCP4017T-104ELT,如图1。MCP4017是一个可编程电阻,通过写入的数值可以改变电阻的大小。重点在于6引脚(W),5引脚(B