0.环境配置:固件库安装路径 C:\Program Files\STMicroelectronics\STM32Cube\Repository
烧录配置:先将其一板子升级成ST_Link,注意要先拨开关ON,再连接电脑;之后用排线将另一板子连接,注意要先拨开关OFF再连接ST_Link(此部分内容看单板介绍,内有脱机烧录等)
1.启用外部晶振时钟 高速HSE,注意此板子无LSE
此板子可选用外部HSE(max72) 或者内部晶振时钟源(max64)
技巧:在HCLK系统时钟填入所需时钟频率(此处为72),按下回撤,可自动配置
2
2.库函数调用在 hal_gpio(外设名).c
3.库函数的毫秒级延时,可直接调用
4.cubemx可自行命名引脚名称,在main.h中define
5.对于uint8_t未定义问题:#include "stdint.h"
6.串口重定向FILE问题:#include<stdio.h>
7.串口清空接收数组memset:#include"string.h"
一、启用时钟树
对应代码 :
void SystemClock_Config(void)
{
RCC_OscInitTypeDef RCC_OscInitStruct = {0};
RCC_ClkInitTypeDef RCC_ClkInitStruct = {0};
/** Initializes the RCC Oscillators according to the specified parameters
* in the RCC_OscInitTypeDef structure.
*/
RCC_OscInitStruct.OscillatorType = RCC_OSCILLATORTYPE_HSE;
RCC_OscInitStruct.HSEState = RCC_HSE_ON;
RCC_OscInitStruct.HSEPredivValue = RCC_HSE_PREDIV_DIV1;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_ON;
RCC_OscInitStruct.PLL.PLLSource = RCC_PLLSOURCE_HSE;
RCC_OscInitStruct.PLL.PLLMUL = RCC_PLL_MUL9;
if (HAL_RCC_OscConfig(&RCC_OscInitStruct) != HAL_OK)
{
Error_Handler();
}
/** Initializes the CPU, AHB and APB buses clocks
*/
RCC_ClkInitStruct.ClockType = RCC_CLOCKTYPE_HCLK|RCC_CLOCKTYPE_SYSCLK
|RCC_CLOCKTYPE_PCLK1|RCC_CLOCKTYPE_PCLK2;
RCC_ClkInitStruct.SYSCLKSource = RCC_SYSCLKSOURCE_PLLCLK;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV2;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_2) != HAL_OK)
{
Error_Handler();
}
}
配置完成后,之后只需单独使能某些外设时钟即可。
二、GPIO输入与输出
1.推挽输出(Out Push Pull):由PMOS和NMOS控制,输出高低电平,有不同的MOS导通直连VDD或VSS,增加控制端口对GPIO口的电流,即驱动能力增大。
2.开漏输出(Out Open Drain):仅控制NMOS,输出控制仅可作用于输出低电平。若控制端输出高电平,可用内部上拉或外接高电平VCC(可达到5v)。好处是控制端输出较小控制电流即可有较大的驱动能力。
以上两种模式均由单片机内部的GPIO控制寄存器来控制。
复用输出则是由片上外设来控制,除此以外与普通输出模式相同。
上拉和下拉输入:在输入IO口后接上下拉电阻,若无输入,则为上\下拉,有输入,则反之?多用于按键功能(先为上拉高电平,按下后为低电平)
浮空输入:IO口直接肖特基触发器(模拟转为数字量),外部输入不确定,(0-max v均有可能)
模拟输入:IO口跳过肖特基触发器,直接输入模拟量至片上,实现对外部信号的采集(ADC?)
IO口驱动电路的响应速度:普通外设LED等选用低速,IIC、USART通讯选用中速
三、中断
1)中断优先级
抢占优先级较小则可以嵌套;抢占优先级相同,需先来后到;若同时发生,则子优先级较小的优先响应;
2)外部中断与事件中断:外部中断需由CPU编写程序(如按键按下触发中断LED函数),事件中断无需经过CPU(如按键按下自动触发ADC数据采集功能)
3)同组GPIO_0共享一组中断线,且其一作为中断源后,同组不可再配置中断源
【例子】设置GPIOA_0 的优先级
1)设置触发方式,因此处为松开按键后才触发中断,即为上升沿触发
2)NVIC中使能中断线,调整优先级
3
3) 初始化函数
4)中断函数调用至回调函数,回调函数自行编写,在对应的.c文件中(如按键则编写在gpio.c),或者编写在main.c也可
四、通信
1.同步通信(IIC\SPI)关键是有时钟信号SCL,异步通信(串口传输)
2.串口1(发送数据)配置,只需配置专用引脚+异步方式+波特率,其余默认即可
3.串口2(接收数据)配置,需配置引脚+异步方式+波特率+中断,其余默认
4.串口2的事件中断:初始化完成后,调用 HAL_UART_Receive 数据接收函数,串口接收到数据后则会触发串口2中断。
(uint8_t*)&rx_data
是将rx_data
强制转换为uint8_t
类型的指针。这种类型转换通常用于在不同数据类型之间进行转换或访问内存中的特定字节。
5.串口1的打印数据:
1)系统已自行初始化完成
2)在usart.c中编写重定向函数,注意main.c、usart.c均需include<stdio.h>
3)记得勾选魔术棒中的微库 Use MicroLib
/*****************************************************
*function: 写字符文件函数
*param1: 输出的字符
*param2: 文件指针
*return: 输出字符的ASCII码
******************************************************/
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t*)&ch, 1, 10);
return ch;
}
/*****************************************************
*function: 读字符文件函数
*param1: 文件指针
*return: 读取字符的ASCII码
******************************************************/
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, (uint8_t*)&ch, 1, 10);
return (int)ch;
}
6.串口2的函数编写
0)串口2即可接收数据产生串口事件中断,也可发送数据,串口回调函数在接收数据产生中断后自行执行(接收本次数据,开启下次中断),无需调用。
1)在usart.c中编写串口2相关的基础函数,方便main调用,注意要在usart.h中声明(回调函数除外)
static uint8_t rx_data;
static uint8_t usart_rx_buf[200];
static uint8_t rx_len = 0;
//HAL_UART_Receive_IT(&huart2,rx_data,1);
//串口2启动函数,用于接收到数据后启用串口中断
void USART2_StartRx(void)
{
HAL_UART_Receive_IT(&huart2, (uint8_t*)&rx_data, 1);
}
//串口2中断回调函数,执行中断时跳转到这里
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)
{
usart_rx_buf[rx_len%200] = rx_data;
rx_len++;
HAL_UART_Receive_IT(&huart2, (uint8_t*)&rx_data, 1);//开启下一次中断。接收UART数据并启用中断,放于接收数据的地址
}
//串口2接收数据
uint16_t USART2_Receive(uint8_t *pdata)
{
memcpy(pdata, (uint8_t*)usart_rx_buf ,rx_len);
return rx_len;
}
//串口2发送数据
void USART2_Transmit(uint8_t *pData, uint16_t Size, uint32_t Timeout)//仅为串口2数据传输函数的基础编写,方便主函数调用
{
HAL_UART_Transmit(&huart2, pData, Size, Timeout);
}
//串口2清空数据
void USART2_ClearBuf(void)
{
rx_len = 0;
memset((uint8_t*)usart_rx_buf, 0, 200);//需要清洗的数组地址,清洗为多少,需要清空的数组大小
}
2)在main函数中定义 保存变量,发送和接收的数组
uint16_t data_len = 0;//保存串口2接收到的数据长度
uint8_t rx_data[200] = {0};
uint8_t tx_data[200] = "AT\r\n";
3)main中启动串口2 发送 接收函数
// 1.启动串口2接收(中断方式),此时开始接收数据
USART2_StartRx();
// 2.串口2发送AT指令,异步进行不会干扰
USART2_Transmit(tx_data, sizeof(tx_data), 500);
4)while中不断接收串口2的receive数据,并判断接收数据长度大于0后才printf,注意函数被赋值的是其返回值,优先明确其返回值的定义
data_len = USART2_Receive(rx_data);//赋值此函数,即为赋值其返回值,其为接收到数据的长度
if (data_len > 0) //长度大于0,接收到数据
{
printf("Receive: %s\n\r", rx_data); // 打印接收的数据?why %s
USART2_ClearBuf(); // 清空接收的buf
data_len = 0; //清空主函数定义的变量,准备下一次接收
}
四、WIFI模块(ESP8266) + AT指令
1.AT指令使用方式:先用测试指令观察可以设置那些参数值,再用查询指令明确当前参数,最后用设置指令设置参数。或有执行指令,无需设参,直接执行。
对于第二点 缺省值 的补充解释:
开关回显功能:是否显示自行发送的指令
五、网络通信
1.网络通信基础:主机通过IP地址联系从机,从机再根据端口号(1024以上)执行相应应用。
2.网络传输协议:TCP和UDP
TCP和UDP是两种常用的网络传输协议,它们在数据传输的方式和特点上有所区别。
-
TCP(传输控制协议)是一种面向连接的协议,它提供可靠的数据传输。TCP通过建立连接、数据分段、确认和重传等机制来确保数据的可靠性和顺序性。TCP适用于对数据传输的可靠性要求较高的场景,例如文件传输、网页浏览等。
-
UDP(用户数据报协议)是一种无连接的协议,它提供不可靠的数据传输。UDP将数据封装成数据包,然后直接发送出去,不需要建立连接和确认机制。UDP适用于对数据传输实时性要求较高、对数据可靠性要求较低的场景,例如音视频传输、实时游戏等。
3.TCP连接流程
补充解释:
1)复位重启
2)模式设置:AT+CWMODE_DEF 用于ESP8266模块的Wi-Fi工作模式,为station模式,WIFI的一个客户端?DEF(default默认值)表示保存到Flash中
3)连接AP AT+CWJAP_DEF,用于设置ESP8266模块连接到指定的Wi-Fi网络,其中,<ssid>
是要连接的Wi-Fi网络的名称,<password>
是该网络的密码。通过执行这个指令,ESP8266模块将会尝试连接到指定的Wi-Fi网络。
4)查看IP,AT+CIFSR,AT+CIFSR是一个AT指令,用于查询ESP8266模块的IP地址。如果,指令执行成功,响应将以"+ CIFSR:<IP address> OK"的形式返回。其中,<IP address>是ESP8266模块的IP地址。
5)创建TCP连接,AT+CIPMUX = 1 , AT+CIPSERVER = 19999,AT+CIPMUX=1,启用多连接模式,设置AT+CIPSERVER=1,9999,启动TCP服务器,并将通讯端口设置为9999
6)AT+CIPSEND = 0,32,0为 Wi-Fi UDP 透传,32表示将长度为32的数据发送到连接ID为0的服务器。
六、项目
1.选用sys- debug 串行调试模式