历史上的今天
返回首页

历史上的今天

今天是:2024年08月30日(星期五)

正在发生

2021年08月30日 | 玩转STM32CubeMX | 串口通讯

2021-08-30 来源:eefocus

1.串口简介

在串行通信中,一个字符一个字符地传输,每个字符一位一位地传输,并且传输一个字符时,总是以“起始位”开始,以“停止位”结束。在进行传输之前,双方一定要使用相同的波特率设置。波特率就是每秒钟传输的数据位数。常用的两种基本串行通信方式包括同步通信和异步通信。我们通常使用的是异步通信,异步通信规定传输的数据格式由起始位(start bit)、数据位(data bit)、奇偶校验位(parity bit)和停止位(stop bit)组成。串口通讯有HAL 库轮询,中断,DMA 三种通信模式:


轮询方式:CPU不断查询IO设备,如设备有请求则加以处理。例如CPU不断查询串口是否传输完成,如传输超过则返回超时错误。轮询方式会占用CPU处理时间,效率较低


中断控制方式:当I/O操作完成时,输入输出设备控制器通过中断请求线向处理器发出中断信号,处理器收到中断信号之后,转到中断处理程序,对数据传送工作进行相应的处理


直接内存存取技术(DMA)方式:所谓直接传送,即在内存与IO设备间传送一个数据块的过程中,不需要CPU的任何中间干涉,只需要CPU在过程开始时向设备发出“传送块数据”的命令,然后通过中断来得知过程是否结束和下次操作是否准备就绪


USART框图

串口通讯过程

2.硬件设计

本实验通过CH340芯片把STM32F1的串口1与PC的USB口进行连接,实现串口连接。串口通讯需要将数据收发管脚交叉连接,电路中的其他部分是自动下载电路部分,目的是控制BOOT的启动模式与复位。用到的硬件资源有:


*指示灯D1


*USART1


3.软件设计

3.1 STM32CubeMX设置

➡️ RCC设置外接HSE,时钟设置为72M

➡️ PC0设置为GPIO推挽输出模式、上拉、高速、默认输出电平为高电平

➡️ USART1选择为异步通讯方式,波特率设置为115200Bits/s,传输数据长度为8Bit,无奇偶校验,1位停止位

➡️ 若使用中断通讯方式,还需要开启串口中断

➡️ 若使用直接内存存取(DMA)方式,除以上步骤外(串口中断要开启,否则程序只能发送一次数据,且不能判断DMA传输是否完成,USART一直处于busy状态)还需要设置DMA传输方向、通道、优先级、数据长度以及指针递增与否

➡️输入工程名,选择工程路径(不要有中文),选择MDK-ARM V5;勾选Generated periphera initialization as a pair of ‘.c/.h’ files per IP ;点击GENERATE CODE,生成工程代码

3.2 MDK-ARM软件编程


轮询方式

/*****usart.c文件中的UART初始化函数以及IO口配置函数*****/

void MX_USART1_UART_Init(void){

    huart1.Instance = USART1;

    huart1.Init.BaudRate = 115200;

    huart1.Init.WordLength = UART_WORDLENGTH_8B;

    huart1.Init.StopBits = UART_STOPBITS_1;

    huart1.Init.Parity = UART_PARITY_NONE;

    huart1.Init.Mode = UART_MODE_TX_RX;

    huart1.Init.HwFlowCtl = UART_HWCONTROL_NONE;

    huart1.Init.OverSampling = UART_OVERSAMPLING_16;

    if (HAL_UART_Init(&huart1) != HAL_OK){

      Error_Handler();

    }

}


void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle){

    GPIO_InitTypeDef GPIO_InitStruct = {0};

    if(uartHandle->Instance==USART1){

    /* USART1 clock enable */

    __HAL_RCC_USART1_CLK_ENABLE();  

    __HAL_RCC_GPIOA_CLK_ENABLE();

    /**USART1 GPIO Configuration    

    PA9     ------> USART1_TX

    PA10     ------> USART1_RX*/

    GPIO_InitStruct.Pin = GPIO_PIN_9;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);


    GPIO_InitStruct.Pin = GPIO_PIN_10;

    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;

    GPIO_InitStruct.Pull = GPIO_NOPULL;

    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    }

}


C语言中的标准库中所用的标准输出函数,默认的输出设备是显示屏,要实现串口或LCD的输出,必须重新定义标准库函数里与输出函数相关的函数,例如printf输出到串口,需要将fputc函数里面的输出指向串口(重定向)

/*****在usart.c中添加如下函数*****/

int fputc(int ch, FILE *f){

    HAL_UART_Transmit(&huart1, (uint8_t *)&ch, 1, 0xffff);

    return ch;

}


/*****main.c文件中编写相关代码*****/

while (1){

    HAL_UART_Transmit(&huart1,"HAL_UART_Transmit Test...",25,0xffff);

    printf("rn printf test...rn");

    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);

    HAL_Delay(1000);

    /* USER CODE END WHILE */

}


中断方式

/*****usart.c文件中的UART初始化函数以及IO口配置函数*****/

void MX_USART1_UART_Init(void){

//....该函数与轮询方式的UART初始化函数相同....

}


void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle){

    GPIO_InitTypeDef GPIO_InitStruct = {0};

    if(uartHandle->Instance==USART1){

    /* USART1 clock enable */

    __HAL_RCC_USART1_CLK_ENABLE();  

    __HAL_RCC_GPIOA_CLK_ENABLE();

    /**USART1 GPIO Configuration    

    PA9     ------> USART1_TX

    PA10     ------> USART1_RX*/

    GPIO_InitStruct.Pin = GPIO_PIN_9;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);


    GPIO_InitStruct.Pin = GPIO_PIN_10;

    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;

    GPIO_InitStruct.Pull = GPIO_NOPULL;

    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USART1 interrupt Init */

    HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);

    HAL_NVIC_EnableIRQ(USART1_IRQn);

    }

}


    找到弱符号中断接收完成回调函数原型,并在usart.c中自定义该回调函数

    __weak void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart)


void HAL_UART_RxCpltCallback(UART_HandleTypeDef *huart){

    if(huart->Instance == USART1){

    HAL_UART_Transmit(&huart1,RxMsg,10,0xffff);//将接收的数据通过串口1发送回去

    HAL_UART_Receive_IT(&huart1,RxMsg,10);     //再次开启接收中断

    }

}


/*****main.c文件中编写相关代码*****/

/* USER CODE BEGIN PV */

uint8_t TxMsg[] = "rn*****USART communication based on IT*****rn";

uint8_t RxMsg[20];

/* USER CODE END PV */

/* USER CODE BEGIN 2 */

HAL_UART_Transmit_IT(&huart1,TxMsg,sizeof(TxMsg));

HAL_UART_Receive_IT(&huart1,RxMsg,10);

/* USER CODE END 2 */

while (1){

    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);

    HAL_Delay(1000);

    /* USER CODE END WHILE */

}


DMA方式

/*****dma.c文件中的DMA初始化函数*****/

void MX_DMA_Init(void) {

    /* DMA controller clock enable */

    __HAL_RCC_DMA1_CLK_ENABLE();

    /* DMA interrupt init */

    /* DMA1_Channel4_IRQn interrupt configuration */

    HAL_NVIC_SetPriority(DMA1_Channel4_IRQn, 0, 0);

    HAL_NVIC_EnableIRQ(DMA1_Channel4_IRQn);

    /* DMA1_Channel5_IRQn interrupt configuration */

    HAL_NVIC_SetPriority(DMA1_Channel5_IRQn, 0, 0);

    HAL_NVIC_EnableIRQ(DMA1_Channel5_IRQn);

}


/*****usart.c文件中的UART初始化函数以及IO口和DMA配置函数*****/

void MX_USART1_UART_Init(void){

//....该函数与轮询方式的UART初始化函数相同....

}


void HAL_UART_MspInit(UART_HandleTypeDef* uartHandle){

    GPIO_InitTypeDef GPIO_InitStruct = {0};

    if(uartHandle->Instance==USART1){

    /* USART1 clock enable */

    __HAL_RCC_USART1_CLK_ENABLE();  

    __HAL_RCC_GPIOA_CLK_ENABLE();

    /**USART1 GPIO Configuration    

    PA9     ------> USART1_TX

    PA10     ------> USART1_RX */

    GPIO_InitStruct.Pin = GPIO_PIN_9;

    GPIO_InitStruct.Mode = GPIO_MODE_AF_PP;

    GPIO_InitStruct.Speed = GPIO_SPEED_FREQ_HIGH;

    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);


    GPIO_InitStruct.Pin = GPIO_PIN_10;

    GPIO_InitStruct.Mode = GPIO_MODE_INPUT;

    GPIO_InitStruct.Pull = GPIO_NOPULL;

    HAL_GPIO_Init(GPIOA, &GPIO_InitStruct);

    /* USART1 DMA Init */

    /* USART1_RX Init */

    hdma_usart1_rx.Instance = DMA1_Channel5;

    hdma_usart1_rx.Init.Direction = DMA_PERIPH_TO_MEMORY;

    hdma_usart1_rx.Init.PeriphInc = DMA_PINC_DISABLE;

    hdma_usart1_rx.Init.MemInc = DMA_MINC_ENABLE;

    hdma_usart1_rx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

    hdma_usart1_rx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

    hdma_usart1_rx.Init.Mode = DMA_NORMAL;

    hdma_usart1_rx.Init.Priority = DMA_PRIORITY_LOW;

    if (HAL_DMA_Init(&hdma_usart1_rx) != HAL_OK){

      Error_Handler();

    }


    __HAL_LINKDMA(uartHandle,hdmarx,hdma_usart1_rx);

    /* USART1_TX Init */

    hdma_usart1_tx.Instance = DMA1_Channel4;

    hdma_usart1_tx.Init.Direction = DMA_MEMORY_TO_PERIPH;

    hdma_usart1_tx.Init.PeriphInc = DMA_PINC_DISABLE;

    hdma_usart1_tx.Init.MemInc = DMA_MINC_ENABLE;

    hdma_usart1_tx.Init.PeriphDataAlignment = DMA_PDATAALIGN_BYTE;

    hdma_usart1_tx.Init.MemDataAlignment = DMA_MDATAALIGN_BYTE;

    hdma_usart1_tx.Init.Mode = DMA_NORMAL;

    hdma_usart1_tx.Init.Priority = DMA_PRIORITY_LOW;

    if (HAL_DMA_Init(&hdma_usart1_tx) != HAL_OK){

      Error_Handler();

    }


    __HAL_LINKDMA(uartHandle,hdmatx,hdma_usart1_tx);

    /* USART1 interrupt Init */

    HAL_NVIC_SetPriority(USART1_IRQn, 0, 0);

    HAL_NVIC_EnableIRQ(USART1_IRQn);

  }

}


/*****main.c文件中编写相关代码*****/

/* USER CODE BEGIN PV */

uint8_t TxMsg[] = "rn*****USART communication based on DMA*****rn";

/* USER CODE END PV */

while (1){

    HAL_UART_Transmit_DMA(&huart1,TxMsg,sizeof(TxMsg));

    HAL_GPIO_TogglePin(GPIOC,GPIO_PIN_0);

    HAL_Delay(1000);

    /* USER CODE END WHILE */


4.下载验证

轮询方式


  • 中断方式

    使用串口助手发送10个字符,串口助手回显发送的数据;串口要发够10个字符才会触发中断;超过10个字符,串口只会发送10个字符(注意不要勾选‘发送新行’)

  • DMA方式

推荐阅读

史海拾趣

创世(CS)公司的发展小趣事

创世公司(CS)的创立源于对未来技术趋势的敏锐洞察。在5G、人工智能、物联网等行业还未广泛崛起的初期,创世公司就预见到这些技术将引领未来电子行业的发展。基于这种战略眼光,创世公司决定专注于SD NAND存储产品的研发和生产。这一决策不仅为公司的后续发展奠定了坚实的基础,也展示了创始团队对未来技术趋势的坚定信心。

亿佰特(EBYTE)公司的发展小趣事

亿佰特在发展过程中,荣获了多项荣誉和奖项。公司成功入选2022年度四川省“专精特新”中小企业名单,这是对公司在细分市场专业化、企业管理精细化、产品或服务特色化、科技成果新颖化等方面的认可。同时,亿佰特还积极履行社会责任,关注环保和公益事业,展现了企业的良好形象和责任感。

以上五个故事方向涵盖了亿佰特在电子行业中的发展过程中的重要方面,希望能够帮助您了解该公司的成长历程。

Esc Electronics Corp公司的发展小趣事

随着全球化进程的加速,Esc开始寻求国际合作和业务拓展的机会。公司与国际知名企业建立了战略合作关系,共同研发新产品、开拓市场。同时,Esc还积极拓展海外市场,通过设立海外分公司、参加国际展会等方式,加强与国际市场的联系和合作。这些努力不仅为Esc带来了更多的业务机会,也提升了公司的国际影响力。

艾谱科(Epticore)公司的发展小趣事

艾谱科公司的创立源于其创始人对电子行业未来发展的独到见解。在21世纪初,随着数字化和智能化技术的飞速发展,创始人意识到电子行业即将迎来一场技术革命。他带领团队深入研究新兴技术,并成功开发出一款具有划时代意义的电子元件——高效能芯片。这款芯片凭借其出色的性能和稳定性,迅速获得了市场的认可,为艾谱科公司的发展奠定了坚实的基础。

Acmelux Taiwan Inc公司的发展小趣事

在电子产品市场竞争激烈的今天,品质成为企业生存和发展的关键。Acmelux Taiwan Inc公司始终坚持品质至上的原则,从原材料采购、生产制造到产品测试,每一个环节都严格把关,确保产品的稳定性和可靠性。正是这种对品质的执着追求,使得Acmelux的产品在市场上赢得了良好的口碑,成为众多客户的首选品牌。

AnalogicTech公司的发展小趣事

AnalogicTech深知品质是企业生存和发展的关键。因此,公司建立了严格的质量管理体系,从原材料采购到产品出厂的每一个环节都进行严格把控。同时,公司还注重客户反馈和需求,不断优化产品和服务,以满足客户的期望和需求。这种对品质的执着追求和对客户的深度关注,使得AnalogicTech赢得了众多客户的信任和忠诚。

问答坊 | AI 解惑

DIY心型LED的活动,,七夕的最好礼物!

点击图标查看详细?嘿嘿 [ 本帖最后由 aldd 于 2008-8-2 00:34 编辑 ]…

查看全部问答>

芯片资料

各位好!目前我手上有个贴片元件,封装为SOT-23-5,元件表面丝印内容简单标注为A1,不知大伙可否遇到过类似元件,求该元件的技术资料,非常感谢!      hgpwgp@yahoo.com.cn…

查看全部问答>

烧写NK的时候出现的错误,附串口消息

我直接从韩国下载的 MP2530F的BSP,编译能通过,在烧写完NK.NB0的时候进入不了系统,串口消息如下,请各位大侠帮我看一下怎么回事,谢谢 NK.nb0 will be downloaded 31457280 bytes at 0x400000 Now, Downloading [ADDRESS:400000h, TOTAL:0x01E0 ...…

查看全部问答>

pocket pc 与 webservice 连接方式?

初识智能设备,要做一个pda点菜系统,我现在用的是vs2005,建的是pocket pc项目,问我应该怎么让pda与webservice连接? 1、在pda端是new一个成员webservice引用还是每进行一个操作new一个局部ws的引用(这样会不会影响效率)? 2、如果是nwe一个成 ...…

查看全部问答>

液晶黑屏

我用的液晶显示器平时显示是正确的 但是偶尔会在初始化之后黑屏了 这样就看不到屏上的信息了 请高手指点一下!! 谢谢…

查看全部问答>

关于PWM的问题!!!

我今天看了周立功的213X的书,PWM(脉宽调制器),里面说到PWMX有单边缘控制模式和双边缘控制模式,请问大侠们这里的单边缘和双边缘是是什么意思?????…

查看全部问答>

从SIM卡上获取语音信箱号码

大家好!    请问大家有人知道,如何获得存放在SIM卡上的语音信箱号码吗?因为有些SIM卡将语音信箱号码预先设置到了SIM卡的某个地方,我现在想把这个号码取出来.那如何做到呢?    在GSM11.11规范中有EF-SDN(6F49)着个文件, 但是 ...…

查看全部问答>

关于用QuartusII仿真的问题??????

今天遇到一个奇怪的问题:用QuartusII仿真的时候,波形图总是不会出现时钟,就只有电平而已,但是程序确定无误是设定了时钟类型的,仿真的时候也设定了,但就是仿真不了!到底是什么问题呢??…

查看全部问答>

PIC单片机的应用设计技巧(转)

PIC单片机的应用设计技巧(转)   document.write(overlap1); 美国微芯公司(Microch{p Technology Inc.)开发的CM0S工艺PIC系列8位单片机(RISC微控制器),特别是 ...…

查看全部问答>

关于ARM开发板

最近想弄块A8或者ARM11的板子玩玩,不知道大家都有没有兴趣如果人多,我们可以组织团购!!~…

查看全部问答>