(一)Day1
1.学习路线
2.基本概念
1.什么是ARM
2.ARM架构分类
3.MCU和MPU
4.DSP和FPGA
总结
在控制显示通讯 —— MCU\MPU —— C语言基础、外设基础、RTOS、 Linux基础、操作系统、网络编程
通讯数据处理算法—— DSP —— 数据处理算法理论知识
大量数据处理、特例的实现 —— FPGA —— 高速接口、音视频算法
STM32开发命名规则
3 嵌入式产品举例
1.智能台灯
无操作系统的MCU项目
功能描述:可以根据外界光照情况调整自身亮度和色温,
也可以通过按钮手动调整,
可以和手机连接,通过app控制,
还能间隔一定时间,提醒用户。
一个主控芯片 + WIFI芯片
系统大致框图
2.智能手环
通常运行RTOS
3电视盒子
运行Linux/Android系统
(二)Day2
1.上手思路
最小系统概念
2.寄存器
存储结构
控制LED 流程:原理图(找到连接的引脚)—— 芯片存储结构图(找到控制寄存器地址)—— 根据手册查看详细信息
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/25b2e3c82fc84ada8d7f980ca47fb98c.png]
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/0bf02e42b9164001882f7e100bdc322e.png]
3 开发方式
4 创建工程
STM32CubeMX创建工程选取MDK-ARM(适用于KEIL的工程),勾选Generate选项
![在这里插入图片描述](https://img-blog.csdnimg.cn/direct/ac398a5cdbae4ea0bcc5bca38af616f8.png
第一个点灯程序
在主题main函数相对应位置
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
HAL_Delay(1000);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
HAL_Delay(1000);
}
/* USER CODE END 3 */
}
5 夜课
C语言指针基础
如何操作GPIO
三种办法
1.参考网上示例
2.看HAL库源码和注释
1.使能时钟
2.初始化配置引脚,里面设置引脚的各个属性
3.如果涉及中断,还需配置中断
4.读引脚函数
5.写引脚函数
- 使用配套资料的 《8_STM32F1HAL库和LL库用户手册.pdf》
(三)Day3
1.时钟系统与GPIO
按键控制灯
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
if (0 == HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin))
{
HAL_Delay(8); // 延时消抖
if (0 == HAL_GPIO_ReadPin(KEY_GPIO_Port, KEY_Pin))
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_RESET);
}
else
{
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_1, GPIO_PIN_SET);
}
}
2. CubeMx时钟配置
判断时钟配置是否正确的两个方法
1.使用HAL库提供的函数HAL_RCC_GetSysClockFreq(),
获取系统时钟频率,再通过串口打印或者debug调试显示结果。
第二个,硬件方法:PA8可以复用为MCO引脚,对外提供时钟输出。
用示波器监控该引脚的输出来判断我们的系统时钟是否设置正确。
(四)Day4
什么是中断
中断有哪些
中断优先级
GPIO 中断
中断与事件的区别
链接: STM32 中断与事件
CubeMX操作中断
1.配置中断引脚
- 降低抢占优先级,勾选NVIC代码初始化
按键中断调用
最后调用HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin) 为虚函数,覆写
static uint8_t key_flag = 0;
void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
if(GPIO_Pin == KEY_Pin)
{
key_flag = ~key_flag;
HAL_GPIO_WritePin(LED_GPIO_Port, LED_Pin, key_flag?GPIO_PIN_RESET:GPIO_PIN_SET);
}
}
通讯
1.串行/并行通讯
2.全双工\半双工\单工传输
3.同步\异步通信
4.串口电平
串口连接时序
5.串口测试
CubeMX配置
实现完串口配置就可以使用 HAL_UART_Receive和HAL_UART_Transmit来接收和发送串口数据
在实现printf格式化输出,需要覆写两个函数,如下 重定向打印输出代码
在 Usart.c中添加如下代码 ,添加头文件 #includ <stdio.h>
/*
* 添加如下代码,可不在工程设置中勾选 Use MicroLIB
*/
#pragma import(__use_no_semihosting)
struct __FILE
{
int a;
};
FILE __stdout;
FILE __stdin;
void _sys_exit(int x)
{
}
/*****************************************************
*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;
}
在主函数中打印测试
printf("百问科技 www.100ask.net\n\r");
printf("UART 实验\n\r");
printf("test char = %c,%c\n\r", 'H', 'c');
printf("test string1 = %s\n\r", "www.100ask.net");
printf("test string2 = %s\n\r", "深圳百问网科技有限公司");
printf("test decimal1 number = %d\n\r", 123456);
printf("test decimal2 number = %d\n\r", -123456);
printf("test hex1 number = 0x%x\n\r", 0x123456);
printf("test hex2 number = 0x%08x\n\r", 0x123456);
printf("test float = %.5f\n\r", 3.1415);
printf("test double = %.10lf\n\r", 3.141592653);
配置串口2,使能串口2的中断用于接收数据
串口终端函数HAL_UART_IRQHandler(&huart2) —— UART_Receive_IT(huart) —— HAL_UART_RxCpltCallback(huart) 虚函数 覆写
串口通讯简要流程
- 重定向打印输出代码 (用于格式化打印输出)
- 覆写串口2中断返回函数,编写串口接收数据函数,发送数据函数,清空数据函数以及启动接收函数
// 串口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);
}
// 串口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)
{
HAL_UART_Transmit(&huart2, pData, Size, Timeout);
}
// 清空串口2接收的数据
void USART2_ClearBuf()
{
rx_len = 0;
memset((uint8_t*)usart_rx_buf, 0, 200);
- 在主函数中 1. 启动串口接收(中断方式) —— 串口发送指令 —— 接受模块返回数据
// 1.启动串口2接收(中断方式)
USART2_StartRx();
// 2.串口2发送AT指令
USART2_Transmit(tx_data,sizeof(tx_data), 500);
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
// 3.接收模块返回的数据
data_len = USART2_Receive(rx_data);
if(data_len > 0) // 接受到数据
{
printf("Receive: %s\r\n", rx_data); // 打印接受数据
USART2_ClearBuf(); // 清空接受的buf
data_len = 0; // 准备下一次接收
}
}
6 夜课
-
中断设置
STM32中断重点理解中断优先级分组,
然后根据中断优先级分组确定抢占优先级级数和子优先级级数。体现在代码编程里,就是根据中断需求,
先使用“HAL_NVIC_SetPriorityGrouping()”函数设置中断优先级分组:
HAL_Init(void)
-&get;HAL_NVIC_SetPriorityGrouping再使用“HAL_NVIC_SetPriority()”函数设置不同中断的抢占优先级级数和子优先级级数:
MX_NVIC_Init(void)
-&get; HAL_NVIC_SetPriority(EXTI0_IRQn, 2, 0);
HAL_NVIC_EnableIRQ(EXTI0_IRQn);
链接: NVIC中断优先级分组
Day5
1. AT指令说明
2. TCP连接流程
指令响应