嵌入式实训——day3

在为期两天的C语言知识回顾之后,我们开始做stm32的基础实验

今天的基础实验内容有:1、点亮一个led灯(呼吸灯的实现)2、定时器的使用 3、串口通信实验

在实验之前呢,需要安装一些软件

链接:https://pan.baidu.com/s/1A8gFiggPVYl8rzdk-Ym99Q 
提取码:uy2c 
(里面有软件及安装说明,个人建议安装软件时 以管理员的身份打开)

在一切做好之后呢,我们开始做实验

一、呼吸灯实验

    实验环境:FS-STM32F103开发平台、STM32CubeMX图形开发软件、Keil软件

    实验原理:只要是对硬件操作,就要首先查看原理图。查看外设是给模块的MCU的哪个引脚相连。FS-STM32F103开发平台上的LED的亮灭状态,与芯片上的引脚I/O输出电平有关,小灯的引脚为PB6,PB7,PB8,为共阳极,这里可以看电路图

 原理其实就是三个不同颜色的led灯,通过颜色强弱组合可以变成不同的颜色。

具体步骤:

  1、打开STM32CubeMX—>点击new project

  2、选择MCU,本次用的芯片为STM32F103

3、配置引脚或选择外设(PB8/PB7/PB6设置为GOPIO_Output)

4、配置时钟(默认时钟8MHZ)

5、创建工程:点击上方project—>Settings

注:工程名和路径必须为英文,如果有中文会出现生成代码不成功的现象,编译器型号选择MDK-ARM V5

6、在code generator里面勾选Generate files的第一个,选择模块化生成代码

 7、打开工程,编写程序

 8、往开发板下载程序

9、查看实验结果

10、代码部分

相应的地方添加如下代码(必须在正确位置添加,不然下次重新生成工程时会被覆盖)

延时函数声明:

1
2
3
4

 

/* USER CODE BEGIN PFP */
/* Private function prototypes -----------------------------------------------*/

void delay_nus(uint16_t time);
/* USER CODE END PFP */

 

led灯代码 

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

 

 

  /* USER CODE BEGIN 3 */
    /****************以下是呼吸灯程序**************/
        for(i=0; i<500; i++)
    { 
/*GPIOB表示PB类端口,GPIO_PIN_8表示PB8端口, GPIO_PIN_SET设置为1高电平*/    
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
        delay_nus(i);
/*递增延时*/

        /*GPIO_PIN_SET设置为0低电平*/ 
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);
        delay_nus(500-i);
/*递减延时*/
    }
        
for(i=0; i<500; i++)
    {       
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);
        delay_nus(i);
        HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
        delay_nus(500-i);
    }
        
/*************以下是三色小灯轮流闪烁*************/
//      HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_RESET);
//      HAL_Delay(1000);
//      HAL_GPIO_WritePin(GPIOB, GPIO_PIN_8, GPIO_PIN_SET);
//      HAL_Delay(1000);
//      HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_RESET);
//      HAL_Delay(1000);
//      HAL_GPIO_WritePin(GPIOB, GPIO_PIN_7, GPIO_PIN_SET);
//      HAL_Delay(1000);
//      HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);
//      HAL_Delay(1000);
//      HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_SET);
//      HAL_Delay(1000);

  }
  
/* USER CODE END 3 */

 

 

 

 

延时函数定义

1
2
3
4
5
6
7
8
9
10
11

 

/* USER CODE BEGIN 4 */
void delay_nus(uint16_t time)
{    
   uint16_t i=
0;  
   while(time--)
   {
      i=
10
      while(i--) ;    
   }
}

/* USER CODE END 4 */

二、定时器实验

  实验原理:

stm32F103芯片提供了8个定时器,其中两个TIM1和TIM8是高级定时器,其余为通用定时器。

TIM1和TIM8挂在APB2总线上,而TIM2-TIM7则挂在APB1总线上。其中TIM1&TIM8称为高级控制定时器(advanced control timer).他们所在的APB2总线也比APB1总线要好。APB2可以工作在72MHz下,而APB1最大是36MHz。

  软件配置:

使用内部时钟源

参考代码:

在main.c里添加如下代码

1
2
3
4

 

  /* USER CODE BEGIN 2 */

 /*设置PB6端口为0*/
    HAL_GPIO_WritePin(GPIOB, GPIO_PIN_6, GPIO_PIN_RESET);

/*开启时钟*/
    HAL_TIM_Base_Start_IT(&htim2);
  
/* USER CODE END 2 */

 

在中断处理函数stm32f1xx_it.c中

我们看到中断处理函数里是调用了另外一个函数,

1
2
3
4
5
6
7
8
9
10
11
12
13

 

/**
* @brief This function handles TIM2 global interrupt.
*/

/*TIME2定时器中断控制*/
void TIM2_IRQHandler(void)
{
  
/* USER CODE BEGIN TIM2_IRQn 0 */

  /* USER CODE END TIM2_IRQn 0 */

  /*时钟中断控制调用*/
  HAL_TIM_IRQHandler(&htim2);
  
/* USER CODE BEGIN TIM2_IRQn 1 */

  /* USER CODE END TIM2_IRQn 1 */
}

追踪一下

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
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131

 

/**
  * @brief  This function handles TIM interrupts requests.
  * @param  htim : TIM  handle
  * @retval None
  */

  /*时钟中断处理函数*/
void HAL_TIM_IRQHandler(TIM_HandleTypeDef *htim)
{
  
/* Capture compare 1 event */
  if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC1) != RESET)
  {
    
if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC1) !=RESET)
    {
      {
        __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC1);
        htim->Channel = HAL_TIM_ACTIVE_CHANNEL_1;

        
/* Input capture event */
        if((htim->Instance->CCMR1 & TIM_CCMR1_CC1S) != 0x00)
        {
          HAL_TIM_IC_CaptureCallback(htim);
        }
        
/* Output compare event */
        else
        {
          HAL_TIM_OC_DelayElapsedCallback(htim);
          HAL_TIM_PWM_PulseFinishedCallback(htim);
        }
        htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
      }
    }
  }
  
/* Capture compare 2 event */
  if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC2) != RESET)
  {
    
if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC2) !=RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC2);
      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_2;
      
/* Input capture event */
      if((htim->Instance->CCMR1 & TIM_CCMR1_CC2S) != 0x00)
      {
        HAL_TIM_IC_CaptureCallback(htim);
      }
      
/* Output compare event */
      else
      {
        HAL_TIM_OC_DelayElapsedCallback(htim);
        HAL_TIM_PWM_PulseFinishedCallback(htim);
      }
      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
    }
  }
  
/* Capture compare 3 event */
  if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC3) != RESET)
  {
    
if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC3) !=RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC3);
      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_3;
      
/* Input capture event */
      if((htim->Instance->CCMR2 & TIM_CCMR2_CC3S) != 0x00)
      {
        HAL_TIM_IC_CaptureCallback(htim);
      }
      
/* Output compare event */
      else
      {
        HAL_TIM_OC_DelayElapsedCallback(htim);
        HAL_TIM_PWM_PulseFinishedCallback(htim);
      }
      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
    }
  }
  
/* Capture compare 4 event */
  if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_CC4) != RESET)
  {
    
if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_CC4) !=RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_IT_CC4);
      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_4;
      
/* Input capture event */
      if((htim->Instance->CCMR2 & TIM_CCMR2_CC4S) != 0x00)
      {
        HAL_TIM_IC_CaptureCallback(htim);
      }
      
/* Output compare event */
      else
      {
        HAL_TIM_OC_DelayElapsedCallback(htim);
        HAL_TIM_PWM_PulseFinishedCallback(htim);
      }
      htim->Channel = HAL_TIM_ACTIVE_CHANNEL_CLEARED;
    }
  }
 
 /* TIM Update event */
  if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_UPDATE) != RESET)
  {
    if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_UPDATE) !=RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_IT_UPDATE);
      HAL_TIM_PeriodElapsedCallback(htim);
//回调函数
    }
  }

  /* TIM Break input event */
  if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_BREAK) != RESET)
  {
    
if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_BREAK) !=RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_IT_BREAK);
      HAL_TIMEx_BreakCallback(htim);
    }
  }
  
/* TIM Trigger detection event */
  if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_TRIGGER) != RESET)
  {
    
if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_TRIGGER) !=RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_IT_TRIGGER);
      HAL_TIM_TriggerCallback(htim);
    }
  }
  
/* TIM commutation event */
  if(__HAL_TIM_GET_FLAG(htim, TIM_FLAG_COM) != RESET)
  {
    
if(__HAL_TIM_GET_IT_SOURCE(htim, TIM_IT_COM) !=RESET)
    {
      __HAL_TIM_CLEAR_IT(htim, TIM_FLAG_COM);
      HAL_TIMEx_CommutationCallback(htim);
    }
  }
}

 

红色标记部分即是我们需要实现的函数。这是一个回调函数,就是当发生中断时调用这个函数,我们可在重写此函数

我们可以将其写在main.c的USER CODE 4 部分

1
2
3
4
5
6

 

/* USER CODE BEGIN 4 */
void HAL_TIM_PeriodElapsedCallback(TIM_HandleTypeDef *htim)
{
    HAL_GPIO_TogglePin(GPIOB, GPIO_PIN_6);
/*PB6端口配置高电平,即点LED*/
}
/* USER CODE END 4 */

三、串口通信实验

  实验原理:

UART和USART的区别:

UART:universal asynchronous receiver and transmitter通用异步收发器USART:universal synchronous asynchronous receiver and transmitter通用同步异步收发器。
从名字上可以看出,USART在UART基础上增加了同步功能,即USART是UART的增强型,事实也确实是这样。但是具体增强到了什么地方呢?
其实当我们使用USART在异步通信的时候,它与UART没有什么区别,但是用在同步通信的时候,区别就很明显了:大家都知道同步通信需要时钟来触发数据传输,也就是说USART相对UART的区别之一就是能提供主动时钟。如stm32的USART可以提供时钟支持ISO7816的智能卡接口。
一般而言,单片机中,名称为UART的接口一般只能用于异步串行通讯,而名称为USART的接口既可以用于同步串行通讯,也能用于异步串行通讯。

 

 

参考代码:

在main函数里写一个以中断方式接受的串口函数

定义一个用来接收数据的数组 

1
2
3
4

 

 

* USER CODE BEGIN PV */
/* Private variables ---------------------------------------------------------*/

    uint8_t RxData[6];
/* USER CODE END PV */

 //打开通道1PWM,那么PB6这个灯就会被点亮

1
2
3
4
5
6
7
8
9
10
11
12
13
14

 

 

  /* USER CODE BEGIN 2 */
    HAL_TIM_PWM_Start(&htim4, TIM_CHANNEL_1);//打开小灯
  /* USER CODE END 2 */

  /* Infinite loop */
  /* USER CODE BEGIN WHILE */
  while (1)
  {
  
/* USER CODE END WHILE */

  /* USER CODE BEGIN 3 */
    HAL_UART_Receive_IT(&huart1,RxData, 6);
  }
  
/* USER CODE END 3 */

 

这里我们在usart.c中去写中断回调函数(也可以在main.c USER CODE BEGIN 4里面写)

回调函数函数里面实现的就是将我们接收到的数据发送到串口助手去显示:

1
2
3
4
5
6

 

/* USER CODE BEGIN 1 */
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *UartHandle)
{
    HAL_UART_Transmit(&huart1,RxData,
6,10);
}

/* USER CODE END 1 */

 

HAL库提供的接收和发送函数都会指定长度,这里就体现了协议的优势了,如我们这里定义了一个uint8_t RxData[6]的数组,接收和发送都指定长度。

 

 

  • 0
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值