目录
一、创建项目
前言:
当STM32接收到字符“stop stm32!”时,停止持续发送“hello windows!”; 当接收到字符“go stm32!”时,持续发送“hello windows!”
STM32采用串口DMA方式,用115200bps或更高速率向上位机连续发送数据
使用设备:
stm32f103c8t6开发板
1、设置RCC
设置高速外部时钟HSE 选择外部时钟源
2、设置串口
点击USATR1
设置MODE为异步通信(Asynchronous)
基础参数:波特率为115200 Bits/s。传输数据长度为8Bit。奇偶检验无,停止位1 接收和发送都使能 > GPIO引脚自动设置 USART1_RX/USART_TX
NVIC Settings一栏使能接收中断
3、设置DMA
点击DMASettings 点击 Add 添加通道
选择USART_RX USART_TX 传输速率设置为中速
DMA传输模式为正常模式
DMA内存地址自增,每次增加一个Byte(字节)
4、DMA基础设置
5、时钟设置
6、项目文件设置
之后GRNERATE CODE创建好工程
二、Keil配置
1、配置下载工具
2、编写代码
定义发送信息,最好是全局变量
char message[]="hello Windows\n";//Êä³öÐÅÏ¢
在while循环中加入如下代码
if(flag==1)
{
// 发送信息
HAL_UART_Transmit(&huart1, (uint8_t *)&message,COUNTOF(message),0xFFFF);
// 延时
HAL_Delay(1000);
}
else if(flag==0)
{
HAL_Delay(1000);
}
在main.c中重写USART1_IRQHandler函数,同时记得删掉stm32f1xx_it.c中的同名函数
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1); //
HAL_UART_Receive_IT(&huart1, (uint8_t *)getBuffer,10); //
}
修改之后的main.c
里面的生成的注释很多,就没有删了
/* USER CODE BEGIN Header */
/**
******************************************************************************
* @file : main.c
* @brief : Main program body
******************************************************************************
* @attention
*
* Copyright (c) 2022 STMicroelectronics.
* All rights reserved.
*
* This software is licensed under terms that can be found in the LICENSE file
* in the root directory of this software component.
* If no LICENSE file comes with this software, it is provided AS-IS.
*
******************************************************************************
*/
/* USER CODE END Header */
/* Includes ------------------------------------------------------------------*/
#include "main.h"
#include "usart.h"
#include "gpio.h"
#include "string.h"
char myBuffer[] = "I have gotten your message: "; //Óû§ÌáʾÐÅÏ¢
char Enter[] = "\r\n"; //»Ø³µ»»ÐÐ
char getBuffer[100]; //Óû§×Ô¶¨ÒåµÄ»º³åÇø
char value;
char str1[] = "go stm32!";
char str2[] = "stop stm32!";
char c;//Ö¸Áî 0:Í£Ö¹ 1:¿ªÊ¼
char message[]="hello Windows\n";//Êä³öÐÅÏ¢
char tips[]="CommandError\n";//Ìáʾ1
char tips1[]="Start.....\n";//Ìáʾ2
char tips2[]="Stop......\n";//Ìáʾ3
int flag=1;//±êÖ¾ 0:Í£Ö¹·¢ËÍ 1.¿ªÊ¼·¢ËÍ
int countofGetBuffer=0;
/* Private includes ----------------------------------------------------------*/
/* USER CODE BEGIN Includes */
/* USER CODE END Includes */
/* Private typedef -----------------------------------------------------------*/
/* USER CODE BEGIN PTD */
/* USER CODE END PTD */
/* Private define ------------------------------------------------------------*/
/* USER CODE BEGIN PD */
/* USER CODE END PD */
/* Private macro -------------------------------------------------------------*/
/* USER CODE BEGIN PM */
/* USER CODE END PM */
/* Private variables ---------------------------------------------------------*/
/* USER CODE BEGIN PV */
/* USER CODE END PV */
/* Private function prototypes -----------------------------------------------*/
void SystemClock_Config(void);
/* USER CODE BEGIN PFP */
/* USER CODE END PFP */
/* Private user code ---------------------------------------------------------*/
/* USER CODE BEGIN 0 */
/* USER CODE END 0 */
/**ep
* @brief The application entry point.
* @retval int
*/
#define COUNTOF(a) (sizeof(a)/sizeof(*(a)))
//jkl
int main(void)
{
/* USER CODE BEGIN 1 */
/* USER CODE END 1 */
/* MCU Configuration--------------------------------------------------------*/
/* Reset of all peripherals, Initializes the Flash interface and the Systick. */
HAL_Init();
/* USER CODE BEGIN Init */
/* USER CODE END Init */
/* Configure the system clock */
SystemClock_Config();
/* USER CODE BEGIN SysInit */
/* USER CODE END SysInit */
/* Initialize all configured peripherals */
MX_GPIO_Init();
MX_USART1_UART_Init();
HAL_UART_Receive_IT(&huart1, (uint8_t *)&value, 1);
//HAL_UART_Receive_IT(&huart1, (uint8_t *)&c, 10);
/* USER CODE BEGIN 2 */
/* USER CODE END 2 */
/* Infinite loop */
/* USER CODE BEGIN WHILE */
while (1)
{
if(flag==1){
//·¢ËÍÐÅÏ¢
HAL_UART_Transmit(&huart1, (uint8_t *)&message,COUNTOF(message),0xFFFF);
//ÑÓʱ
HAL_Delay(1000);
}else if(flag==0){
HAL_Delay(1000);
}
}
}
void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart1){
HAL_UART_IRQHandler(huart1);
getBuffer[countofGetBuffer++]=value;
if(strcmp(getBuffer,str1)==0){
flag = 1;
HAL_UART_Transmit(huart1, (uint8_t *)&tips1, COUNTOF(tips1),0xFFFF);
countofGetBuffer = 0;
memset(getBuffer,0,COUNTOF(getBuffer));
}else if(strcmp(getBuffer,str2)==0){
flag = 0;
HAL_UART_Transmit(huart1, (uint8_t *)&tips2, COUNTOF(tips2),0xFFFF);
countofGetBuffer = 0;
memset(getBuffer,0,COUNTOF(getBuffer));
}
HAL_UART_Receive_IT(huart1, (uint8_t *)&value,1);
}
void USART1_IRQHandler(void)
{
HAL_UART_IRQHandler(&huart1); //¸Ãº¯Êý»áÇå¿ÕÖжϱêÖ¾£¬È¡ÏûÖжÏʹÄÜ£¬²¢¼ä½Óµ÷Óûص÷º¯Êý
HAL_UART_Receive_IT(&huart1, (uint8_t *)getBuffer,10); //Ìí¼ÓµÄÒ»ÐдúÂë
}
/**
* @brief System Clock Configuration
* @retval None
*/
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_HSI;
RCC_OscInitStruct.HSIState = RCC_HSI_ON;
RCC_OscInitStruct.HSICalibrationValue = RCC_HSICALIBRATION_DEFAULT;
RCC_OscInitStruct.PLL.PLLState = RCC_PLL_NONE;
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_HSI;
RCC_ClkInitStruct.AHBCLKDivider = RCC_SYSCLK_DIV1;
RCC_ClkInitStruct.APB1CLKDivider = RCC_HCLK_DIV1;
RCC_ClkInitStruct.APB2CLKDivider = RCC_HCLK_DIV1;
if (HAL_RCC_ClockConfig(&RCC_ClkInitStruct, FLASH_LATENCY_0) != HAL_OK)
{
Error_Handler();
}
}
/* USER CODE BEGIN 4 */
/* USER CODE END 4 */
/**
* @brief This function is executed in case of error occurrence.
* @retval None
*/
void Error_Handler(void)
{
/* USER CODE BEGIN Error_Handler_Debug */
/* User can add his own implementation to report the HAL error return state */
__disable_irq();
while (1)
{
}
/* USER CODE END Error_Handler_Debug */
}
#ifdef USE_FULL_ASSERT
/**
* @brief Reports the name of the source file and the source line number
* where the assert_param error has occurred.
* @param file: pointer to the source file name
* @param line: assert_param error line source number
* @retval None
*/
void assert_failed(uint8_t *file, uint32_t line)
{
/* USER CODE BEGIN 6 */
/* User can add his own implementation to report the file name and line number,
ex: printf("Wrong parameters value: file %s on line %d\r\n", file, line) */
/* USER CODE END 6 */
}
#endif /* USE_FULL_ASSERT */
3、烧录进芯片中
三、运行结果
四、以更高的波特率向上位机连续发送数据
1、创建项目/项目修改
其实大体和前面的一样,只需要在USART设置时,修改一下参数即可,这里的参数最好不要随便输入,应该是参考了调试助手的波特率之后再进行输入,比如:这里输入了128000,这是软件有的波特率
2、代码
如上
3、烧录
4、运行
要将这里的波特率进行对应的修改,来保证输出的正确性
五、DMA简介
1、什么是DMA
DMA(Direct Memory Access,直接存储器访问) 是所有现代电脑的重要特色,它允许不同速度的硬件装置来沟通,而不需要依赖于 CPU 的大量中断负载。
2、原理
DMA 传输将数据从一个地址空间复制到另外一个地址空间。当CPU 初始化这个传输动作,传输动作本身是由 DMA 控制器来实行和完成。典型的例子就是移动一个外部内存的区块到芯片内部更快的内存区。像是这样的操作并没有让处理器工作拖延,反而可以被重新排程去处理其他的工作。DMA 传输对于高效能 嵌入式系统算法和网络是很重要的。
在实现DMA传输时,是由DMA控制器直接掌管总线,因此,存在着一个总线控制权转移问题。即DMA传输前,CPU要把总线控制权交给DMA控制器,而在结束DMA传输后,DMA控制器应立即把总线控制权再交回给CPU。一个完整的DMA传输过程必须经过DMA请求、DMA响应、DMA传输、DMA结束4个步骤。
1、请求
CPU对DMA控制器初始化,并向I/O接口发出操作命令,I/O接口提出DMA请求。
2、响应
DMA控制器对DMA请求判别优先级及屏蔽,向总线裁决逻辑提出总线请求。当CPU执行完当前总线周期即可释放总线控制权。此时,总线裁决逻辑输出总线应答,表示DMA已经响应,通过DMA控制器通知I/O接口开始DMA传输。
3、传输
DMA控制器获得总线控制权后,CPU即刻挂起或只执行内部操作,由DMA控制器输出读写命令,直接控制RAM与I/O接口进行DMA传输。
在DMA控制器的控制下,在存储器和外部设备之间直接进行数据传送,在传送过程中不需要中央处理器的参与。开始时需提供要传送的数据的起始位置和数据长度。
4、结束
当完成规定的成批数据传送后,DMA控制器即释放总线控制权,并向I/O接口发出结束信号。当I/O接口收到结束信号后,一方面停 止I/O设备的工作,另一方面向CPU提出中断请求,使CPU从不介入的状态解脱,并执行一段检查本次DMA传输操作正确性的代码。最后,带着本次操作结果及状态继续执行原来的程序。
由此可见,DMA传输方式无需CPU直接控制传输,也没有中断处理方式那样保留现场和恢复现场的过程,通过硬件为RAM与I/O设备开辟一条直接传送数据的通路,使CPU的效率大为提高。
六、总结
本次的试验中的难点是要接收一个不固定长度的字符串,就需要自己实现一个接收字符串的函数。