STM32串口打印文本和DMA

具体题目和个人想法

        (1)用直接配置串口的方式,向PC传输一句话,(2)在内存中存储一句话,并用DMA配置串口向PC传输。这是原题,笔者因为不可抗力(看错题了)就把输入输出一起做了,所以大伙凑合着看吧doge

        在STM32上的串口是USB转串口,函数主要是USART1,含有两个引脚,分别是USART1_TX(输出)对应引脚PA9,USART1_RX(接收)对应引脚PA10,那么在我们使用DMA(直接内存访问)之前先编写usart.h和usart.c来实现PC端的发送和单片机端的接收。

编写usart(串口)头文件及其初始化

        刚刚在前文提到了USART1这一串口,大家可以直接go to define找到stm32f10x_usart.h,那么这就是我们编写串口函数时所必须的头文件。

        同样,我们这里介绍一下如何使用串口输出字符或者是字符串,其实和平常C语言编程思路大差不差,唯一的问题在于我们每一个变量都是指针指向所输入的字符的地址,字符串就构造数组存储,再指向数组即可。接下来看一看sendbyte和sendstring。

void Usart_SendByte( USART_TypeDef * pUSARTx,uint8_t ch)//一个指针和8位字符(字符8位)
{
	USART_SendData(pUSARTx,ch);
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE)==RESET);
	}//获取该指针并将FLAG RESET



void Usart_SendString( USART_TypeDef * pUSARTx,char *str)//char型的数组指针
{
	unsigned int k=0;
	do
	{
		Usart_SendByte( pUSARTx, *(str +k));//依次读取字符输出形成字符串
		k++;
	}
	while(*(str+k)!='\0');//判断是否输出完毕
	while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)//重置
	{}
}

        接着就是和之前一样的,因为usart仍然由GPIO寄存器控制,所以和之前一样的GPIO初始化配置就行了...吗?同学们需要注意到这次和之前不同,前面的LED和beep我们的1/0都是通过GPIO直接控制的,所以不需要去考虑如何断开的问题,但是串口一旦插上去一定是都处于相互传输的状态,那我们怎么去让他停止呢?

        这里我们就需要另一个非常重要的函数——中断函数了,它所作的事情就是到时间了就直接中断,我们来看看他的函数:

static void NVIC_Configuration(void)
{
		NVIC_InitTypeDef NVIC_InitStruct;//初始化
		NVIC_PriorityGroupConfig (NVIC_PriorityGroup_2 );//优先级族为2
		NVIC_InitStruct.NVIC_IRQChannel = USART_IRQ;//确定控制的中断通道是usart
		NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
		NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;//优先权均定为1
		NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;//时钟使能
		NVIC_Init(&NVIC_InitStruct);
}

那么我们来看看编写好的usart.c和usart.h吧(注意波特率统一,笔者这里给的是115200)

#include "stm32f10x_gpio.h"
#include "stm32f10x.h"
#include "stm32f10x_usart.h"
#include "usart.h"
#include <stdio.h>

static void NVIC_Configuration(void)
{
		NVIC_InitTypeDef NVIC_InitStruct;
		NVIC_PriorityGroupConfig (NVIC_PriorityGroup_2 );
		NVIC_InitStruct.NVIC_IRQChannel = USART_IRQ;
		NVIC_InitStruct.NVIC_IRQChannelPreemptionPriority = 1;
		NVIC_InitStruct.NVIC_IRQChannelSubPriority = 1;
		NVIC_InitStruct.NVIC_IRQChannelCmd = ENABLE;
		NVIC_Init(&NVIC_InitStruct);
}



void USART_Config(void)
{
		GPIO_InitTypeDef GPIO_InitStructure;
	
		USART_InitTypeDef USART_InitStructure;
	
		USART_GPIO_APBxClkCmd(USART1_GPIO_CLK,ENABLE);
	
		USART_APBxClkCmd(USART_CLK,ENABLE);

		GPIO_InitStructure.GPIO_Pin = USART1_TX_GPIO_PIN;
		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;//复用推挽输出
		GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
		GPIO_Init(USART1_TX_GPIO_PORT, &GPIO_InitStructure);

		GPIO_InitStructure.GPIO_Pin = USART1_RX_GPIO_PIN;		
		GPIO_InitStructure .GPIO_Mode = GPIO_Mode_IN_FLOATING ;//浮空输入
  	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz; 
		GPIO_Init(USART1_RX_GPIO_PORT, &GPIO_InitStructure);
  
		USART_InitStructure .USART_BaudRate =USART_BAUDRATE;
		USART_InitStructure .USART_WordLength = USART_WordLength_8b ;
		USART_InitStructure .USART_StopBits = USART_StopBits_1 ;
		USART_InitStructure .USART_Parity = USART_Parity_No ;
		USART_InitStructure .USART_HardwareFlowControl = USART_HardwareFlowControl_None ;
		USART_InitStructure .USART_Mode = USART_Mode_Rx |USART_Mode_Tx ;
		USART_Init (USART1,&USART_InitStructure );
		
		USART_ClearFlag(USART1,USART_FLAG_TC);

		NVIC_Configuration();
		USART_ITConfig (USARTx,USART_IT_RXNE ,ENABLE );
		USART_Cmd (USARTx,ENABLE);
}

void Usart_SendByte( USART_TypeDef * pUSARTx,uint8_t ch)
{
	USART_SendData(pUSARTx,ch);
	while (USART_GetFlagStatus(pUSARTx, USART_FLAG_TXE)==RESET);
	}



void Usart_SendString( USART_TypeDef * pUSARTx,char *str)
{
	unsigned int k=0;
	do
	{
		Usart_SendByte( pUSARTx, *(str +k));
		k++;
	}
	while(*(str+k)!='\0');
	while(USART_GetFlagStatus(pUSARTx,USART_FLAG_TC)==RESET)
	{}
}

void USART_IRQHandler(void)//将receive的data传出
{
  uint8_t ucTemp;
  if(USART_GetITStatus (USART1 ,USART_IT_RXNE)!=RESET )
		{
    ucTemp = USART_ReceiveData (USART1);
		USART_SendData (USART1,ucTemp );
		//很熟悉的方式(临时参数)
		while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
		}
		USART_ClearFlag(USART1,USART_FLAG_TC);
}

#ifndef __USART_H
#define	__USART_H

#include "stm32f10x.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_gpio.h"

void USART_Config(void);
static void NVIC_Configuration(void);
void Usart_SendByte( USART_TypeDef * pUSARTx,uint8_t ch);
void Usart_SendString( USART_TypeDef * pUSARTx,char *str);
void USART_IRQHandler(void);
//记得一定要声明

#define USARTx  USART1
#define USART_BAUDRATE  115200
#define USART1_GPIO_CLK 	    RCC_APB2Periph_GPIOA

#define USART_GPIO_APBxClkCmd  RCC_APB2PeriphClockCmd 


#define USART1_RX_GPIO_PORT    	GPIOA			             
#define USART1_RX_GPIO_CLK 	    RCC_APB2Periph_GPIOA		
#define USART1_RX_GPIO_PIN				GPIO_Pin_10

#define USART1_TX_GPIO_PORT    	GPIOA			             
#define USART1_TX_GPIO_CLK 	    RCC_APB2Periph_GPIOA		
#define USART1_TX_GPIO_PIN				GPIO_Pin_9

#define USART_APBxClkCmd  RCC_APB2PeriphClockCmd
#define USART_CLK  RCC_APB2Periph_USART1 

#define USART_IRQ  USART1_IRQn
#define USART_IRQHandler  USART1_IRQHandler

#define USART_TX_DMA_CHANNEL  DMA1_Channel4//懒得删了大家凑合看


#define USART_DR_ADDRESS  (USART1_BASE+0x04)//给出地址,可以在库函数中查

#define SENDBUFF_SIZE  5000//预留的内存量



#endif

主函数(1)

         看看还没有用DMA,可以输入输出的主函数吧

#include "stm32f10x.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_gpio.h"
#include "usart.h"

int main (viod)
{
    USART_Config();
    while(1)
    {}
}

        打开串口调试助手可以看到Rx和Tx

        进行输入就会在上面产生字符,同时Rx和Tx的Bytes是同时增加,这样就完成了PC端输出单片机接收和单片机输出OC端接收。

编写DMA文件

        DMA本质上是直接内存访问的寄存器,那么既然是寄存器,就和GPIO的差不了太多,但是地址时钟等等大家需要仔细辨别一下。老样子,先源文件后头文件。

#include "stm32f10x.h"
#include "stm32f10x_dma.h"
#include "dma.h"


void DMAx_Init(DMA_Channel_TypeDef* DMAy_Channelx,u32 par,u32 mar,u16 ndtr)
{
	DMA_InitTypeDef  DMA_InitStructure;
	//定义初始化结构体
	RCC_AHBPeriphClockCmd(RCC_AHBPeriph_DMA1,ENABLE);//时钟使能
	
	DMA_InitStructure.DMA_PeripheralBaseAddr = par;//par为基地址的名称变量,便于修改
	DMA_InitStructure.DMA_MemoryBaseAddr = mar;//mar为寄存地址名称变量,便于修改
	DMA_InitStructure.DMA_DIR = DMA_DIR_PeripheralDST;
	DMA_InitStructure.DMA_BufferSize = ndtr;//输入的数据大小设为变量ndtr便于修改
	DMA_InitStructure.DMA_PeripheralInc = DMA_PeripheralInc_Disable;
	DMA_InitStructure.DMA_MemoryInc = DMA_MemoryInc_Enable;
	DMA_InitStructure.DMA_PeripheralDataSize = DMA_PeripheralDataSize_Byte;
	DMA_InitStructure.DMA_Mode = DMA_Mode_Normal;//dma模式为正常
	DMA_InitStructure.DMA_Priority = DMA_Priority_Medium;//优先级为中
	DMA_InitStructure.DMA_M2M = DMA_M2M_Disable;
	DMA_Init(DMAy_Channelx,&DMA_InitStructure);
}

void DMAx_Enable(DMA_Channel_TypeDef* DMAy_Channelx,u16 ndtr)
{    //此函数为了中断后重充能重置,可以直接使能编进上一个函数中
	DMA_Cmd(DMAy_Channelx,DISABLE);
	DMA_SetCurrDataCounter(DMAy_Channelx,ndtr);
	DMA_Cmd(DMAy_Channelx,ENABLE);
}


#ifndef __DMA_H
#define	__DMA_H

#include "stm32f10x.h"
#include "stm32f10x_dma.h"
#include "stm32f10x_usart.h"
#include "usart.h"


void DMAx_Init(DMA_Channel_TypeDef* DMAy_Channelx,u32 par,u32 mar,u16 ndtr);
void DMAx_Enable(DMA_Channel_TypeDef* DMAy_Channelx,u16 ndtr);




#endif

主函数(2)

        那么话不多说,直接看主函数代码:

#include "stm32f10x.h"
#include "stm32f10x_usart.h"
#include "stm32f10x_gpio.h"
#include "usart.h"
#include "dma.h"

#define send_buf_len    1
//后续的输入数据长度,可以随便设,决定你后续在输出过指定的string后输出多少字节
u8 send_buf[send_buf_len ];


int main (void)
{
	DMAx_Init(DMA1_Channel4,(u32)&USART1->DR,(u32)send_buf,send_buf_len);
	USART_Config();
	

	Usart_SendString (USART1,"any words you want\n");//字符串随便写,除了中文,没ASSIC码
	DMAx_Enable(DMA1_Channel4,send_buf_len);
	USART_DMACmd(USART1,USART_DMAReq_Tx,ENABLE);
	while(1)
	{
		if(DMA_GetFlagStatus(DMA1_FLAG_TC4)!=RESET)
		{
			DMA_ClearFlag (DMA1_FLAG_TC4);
			break;
		}
	}
}

在串口调试助手看看实现的功能

完美输出!

  • 2
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值