Sorry, your browser cannot access this site
This page requires browser support (enable) JavaScript
Learn more >

MengFanjun的博客

新学期新气象,新学期我们要学32了,之前虽然学了一点点,但是学的都不是很系统,这里终于能系统的学习一下32了,从原理角度进行一下学习。

我的基本配置:STM32CubeMX、Jlink、STM32F103RCT6 MINI

STM32MINI就是我们学校上课用的32 在这里插入图片描述

第一节课

嵌入式就是在单片机上跑操作系统 在这里插入图片描述 在这里插入图片描述 STM32芯片内部 在这里插入图片描述 这是STM32的命名规则 在这里插入图片描述 在这里插入图片描述 时钟最高72M

在这里插入图片描述 PIN to PIN兼容是指两款芯片的引脚数目一样,功能一样,大小也一样

在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 在这里插入图片描述 通过修改BOOT0和BOOT1的方式来修改32的启动方式,利用跳线帽改这个 在这里插入图片描述 将2,4等引脚短接来修改其启动方式

在这里插入图片描述 在这里插入图片描述 ### 第一节课课后练习:点灯 灯的连线 在这里插入图片描述

1.配置好Cube的Project Manager

路径和工程名称设置 在这里插入图片描述 Code Generator设置 在这里插入图片描述 #### 2.时钟树设置 都改成最高的 在这里插入图片描述 #### 3.RCC设置 在这里插入图片描述 #### 4.Debug模式设置 在这里插入图片描述 #### 5.LED0引脚设置 设置为GPIO_Output 在这里插入图片描述 #### 6.生成代码 在这里插入图片描述

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
void MX_GPIO_Init(void)
{

GPIO_InitTypeDef GPIO_InitStruct = {0};

/* GPIO Ports Clock Enable */
__HAL_RCC_GPIOC_CLK_ENABLE();
__HAL_RCC_GPIOD_CLK_ENABLE();
__HAL_RCC_GPIOA_CLK_ENABLE();
__HAL_RCC_GPIOB_CLK_ENABLE();

/*Configure GPIO pin Output Level */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);

/*Configure GPIO pin : PA8 */
GPIO_InitStruct.Pin = GPIO_PIN_8;
GPIO_InitStruct.Mode = GPIO_MODE_OUTPUT_PP;
GPIO_InitStruct.Pull = GPIO_NOPULL;
GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_LOW;
HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

}

下面是标准库的配置

1
2
3
4
5
6
7
8
9
10
11
12
13
14
void LED_Init(void)
{
GPIO_InitTypeDef GPIO_InitTypeStrucre;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOD,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);

GPIO_InitTypeStrucre.GPIO_Mode=GPIO_Mode_Out_PP;
GPIO_InitTypeStrucre.GPIO_Pin=GPIO_Pin_8 ;
GPIO_InitTypeStrucre.GPIO_Speed=GPIO_Speed_50MHz;

GPIO_Init(GPIOA,&GPIO_InitTypeStrucre);
GPIO_SetBits(GPIOA,GPIO_Pin_8 );
}

7.在主函数while中写出灯的亮灭

HAL_Delay(1)实际延时时间多于1ms一点

1
2
3
4
5
6
/* USER CODE END WHILE */
/* USER CODE BEGIN 3 */
HAL_Delay(300);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
HAL_Delay(300);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
#### 8.配置Jlink 在这里插入图片描述 #### 9.检测芯片 注意:要先给芯片上电,再连接Jlink 在这里插入图片描述 #### 10.编译后下载 在这里插入图片描述 ## 第二节课 什么是看门狗?

是一个定时器,将里面的数值加到一定数值之后,会被复位

所以在程序中每隔多少秒要把看门狗复位

看门狗主要用于无人看管的程序,防止程序跑飞了

GPIO:General Purpose Input Output,通用输入输出 输出三种:1.推挽2.开漏3.关闭 在这里插入图片描述 ### 第二节课课后练习:按键控制灯的亮灭

1.配置好基础配置,和上面前4步一样

2.启用按键和LED的引脚

在这里插入图片描述 #### 3.配置好GPIO KEY0采用上拉模式和输入模式 我一般习惯把名字起的和原理图一模一样,这样代码读起来方便 在这里插入图片描述 #### 4.在while中写出按键检测

1
2
3
4
5
6
7
8
9
10
11
12
13
while (1)
{
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)==GPIO_PIN_RESET)
{
HAL_GPIO_TogglePin(LED0_GPIO_Port,LED0_Pin);
while(HAL_GPIO_ReadPin(KEY0_GPIO_Port, KEY0_Pin)==GPIO_PIN_RESET);
}
}
/* USER CODE END WHILE */
}

5.编译后下载成功

下载后要先按一下Reset才能成功执行

第三节课

第三节课课后练习:外部中断控制灯

1.配置好基础配置,和第一节课4步一样

在这里插入图片描述 在这里插入图片描述

2.配置按键的GPIO模式

在这里插入图片描述 #### 3.在主函数中让程序执行LED0的亮灭 让LED0闪烁,LED1灭

1
2
3
4
5
6
7
8
9
10
11
while (1)
{
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
HAL_Delay(300);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
HAL_Delay(300);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
}

4. 在stm32f1xx_hal_gpio.c中找到中断回调函数

如果按下按键,则LED1亮,表示进入外部中断

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{
/* Prevent unused argument(s) compilation warning */
UNUSED(GPIO_Pin);
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_GPIO_EXTI_Callback could be implemented in the user file
*/
if(GPIO_Pin==GPIO_PIN_1)
{

if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_1)==0)
{
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
}
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_1);
}
}

#### 5.编译后成功下载

第四节课

第四节课系统学习了外部中断 ### 第四节课课后练习:在while(1)中执行灯的同步闪烁,按下KEY0按键,灯闪烁加快20次,按下WKUP,灯交替闪烁20次,KEY0的优先级更高 #### 1.配置好基础配置 #### 2.配置按键的GPIO 在CUBE中都设置为GPIO_EXTI模式 在这里插入图片描述 因为KEY0接地,我们配置成上拉模式 在这里插入图片描述 同理,配置WKUP 在这里插入图片描述 #### 3.在NVIC中配置中断优先级 数字越小,优先级越高 在这里插入图片描述 #### 4.配置两个灯为推挽输出 在这里插入图片描述

5.在while(1)中写出同步闪烁

1
2
3
4
5
6
7
8
9
10
11
12
13
while (1)
{
/* USER CODE END WHILE */

/* USER CODE BEGIN 3 */
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_RESET);
delay_ms(500);
HAL_GPIO_WritePin(GPIOA, GPIO_PIN_8, GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOD, GPIO_PIN_2, GPIO_PIN_SET);
delay_ms(500);
}
/* USER CODE END 3 */

delay_ms

1
2
3
4
5
6
7
8
9
10
11
12
13
14
//毫秒延时
void delay_ms(uint16_t nms)
{
uint32_t temp;
SysTick->LOAD = 9000*nms;
SysTick->VAL=0X00;//清空计数器
SysTick->CTRL=0X01;//使能,减到零是无动作,采用外部时钟源
do
{
temp=SysTick->CTRL;//读取当前倒计数值
}while((temp&0x01)&&(!(temp&(1<<16))));//等待时间到达
SysTick->CTRL=0x00; //关闭计数器
SysTick->VAL =0X00; //清空计数器
}

6.在stm32f10x_hal_gpio.c中写中断回调函数

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
__weak void HAL_GPIO_EXTI_Callback(uint16_t GPIO_Pin)
{



/* Prevent unused argument(s) compilation warning */
UNUSED(GPIO_Pin);
/* NOTE: This function Should not be modified, when the callback is needed,
the HAL_GPIO_EXTI_Callback could be implemented in the user file
*/

if(GPIO_Pin==GPIO_PIN_1)
{

if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_1)==0)
{
for(int i=0;i<20;i++)
{
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,GPIO_PIN_RESET);
delay_ms(200);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,GPIO_PIN_SET);
delay_ms(200);

}
}
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_1);
}
if(GPIO_Pin==GPIO_PIN_0)
{

if(HAL_GPIO_ReadPin(GPIOA,GPIO_PIN_0)==0)
{
for(int i=0;i<20;i++)
{
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_RESET);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,GPIO_PIN_SET);
delay_ms(200);
HAL_GPIO_WritePin(GPIOD,GPIO_PIN_2,GPIO_PIN_SET);
HAL_GPIO_WritePin(GPIOA,GPIO_PIN_8,GPIO_PIN_RESET);
delay_ms(200);
}
}
__HAL_GPIO_EXTI_CLEAR_IT(GPIO_PIN_0);
}

}

7.编译成功后下载

在这个作业中不要将按键设置成浮空,浮空状态会有点问题,要根据引脚设置成需要的状态

第五节课

  • 高级定时器 TIM1 TIM8 在APB1上
  • 通用定时器 TIM2 TIM3 TIM4 TIM5 在APB2上
  • 基本定时器 TIM6 TIM7 在APB1上

在这里插入图片描述 周期表 p n u m 1 K M G T 更新事件Update event(UE) 可以把CNT清零 在这里插入图片描述

1
定时器时间t=1/Tout

如果使能影子寄存器,影子寄存器会在更新事件发生时,将内部数值更新到ARR

ARR是计算时间间隔所以要加1 因为PSC不能为0,所以要加上1 在这里插入图片描述 ### 第五节课课后练习:定时器实现灯的500ms间隔闪烁,和另一个灯的700ms闪烁 #### 1.配置好基础配置 #### 2.打开TIM2和TIM3 在这里插入图片描述 arr和psc的计算过程

1
2
3
(4999+1)*(7199+1)=36000000
72000000/36000000=2
1/2=0.5s=500ms
在这里插入图片描述

3.在NVIC中设置优先级

在这里插入图片描述

4.设置灯为推挽输出

在这里插入图片描述

5.打开定时器中断

main.c

1
2
3
/* USER CODE BEGIN PV */
static int i=0;
/* USER CODE END PV */
1
2
3
4
 /* USER CODE BEGIN 2 */
HAL_TIM_Base_Start_IT(&htim2);
HAL_TIM_Base_Start_IT(&htim3);
/* USER CODE END 2 */

在stm32f10x_hal_tim.c中找到中断回调函数,在main.c中重定义

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
if(htim==&htim2)
{
HAL_GPIO_TogglePin(GPIOA,GPIO_PIN_8);//对GPIO口的电平进行反转(低-高,高—低)
}
if(htim==&htim3)
{
if(++i>=700)
{
i=0;
HAL_GPIO_TogglePin(GPIOD,GPIO_PIN_2);//对GPIO口的电平进行反转(低-高,高—低)
}
}

6.编译后成功下载

第六节课

第六节课课后练习:通过两个按键利用PWM控制灯的亮灭

1.配置好基础配置

2.打开TIM1_CH1

在这里插入图片描述 #### 2.在NVIC中打开中断 在这里插入图片描述 #### 3.设置两个按键的GPIO 在这里插入图片描述 #### 4.写出按键检测代码和启动PWM

1
2
3
4
5
6
/* USER CODE BEGIN 1 */
int i=500;
/* USER CODE END 1 */
/* USER CODE BEGIN 2 */
HAL_TIM_PWM_Start(&htim1,TIM_CHANNEL_1); // 使能PWM输出
/* USER CODE END 2 */
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
  /* USER CODE BEGIN 3 */
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_1)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_1)==GPIO_PIN_RESET)
{
i=i+1;
htim1.Instance->CCR1 = i;
HAL_Delay(1);
while(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_1)==GPIO_PIN_RESET);
}
}
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)==GPIO_PIN_RESET)
{
HAL_Delay(10);
if(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)==GPIO_PIN_RESET)
{
i=i-1;
htim1.Instance->CCR1 = i;
HAL_Delay(1);
while(HAL_GPIO_ReadPin(GPIOC,GPIO_PIN_13)==GPIO_PIN_RESET);
}
}
}
/* USER CODE END 3 */

5.编译后下载

第七节课

第七节课课后作业:串口的收发回显测试

1.配置好基础配置

2.打开串口

设置异步模式和打开中断 在这里插入图片描述 #### 3.在main.c中添加fputc fgetc

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
/**
* 函数功能: 重定向c库函数printf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fputc(int ch, FILE *f)
{
HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);
return ch;
}

/**
* 函数功能: 重定向c库函数getchar,scanf到DEBUG_USARTx
* 输入参数: 无
* 返 回 值: 无
* 说 明:无
*/
int fgetc(FILE *f)
{
uint8_t ch = 0;
HAL_UART_Receive(&huart1, &ch, 1, 0xffff);
return ch;
}

4.主函数代码

定义了一个字符串

1
2
3
/* USER CODE BEGIN 1 */
char str[10];
/* USER CODE END 1 */

因为scanf在单片机中并不是阻塞式接收,所以我们要将其改为阻塞式的

1
2
3
4
5
6
7
8
9
10
/* USER CODE BEGIN 3 */
printf("测试发送\n");
HAL_Delay(100);
str[0]=0;
while(str[0] == 0)
{
scanf("%s",str);
}//使其变成手动的阻塞式接收
HAL_Delay(1000);
printf("output:%s\n",str);

5.编译下载

可以发送也可以接收 在这里插入图片描述

评论