您的位置:首页 > 其它

STM32 串行通信 USART 程序例举

2014-05-02 19:07 316 查看
STM32 串行通信 USART 的笔记讲解连接/article/9902798.html

1、串行通信
软件仿真STM32通过串口USART1发送26个英文字母(配置寄存器)

/**************************************************************************************************
*	硬件平台:STM32F103VC
*	学习重点:GPIOx的位绑定
*	实现功能:软件仿真,实现STM32通过USART1发送数据
*	配置寄存器实现(其中打开系统时钟和GPIO引脚的配置是通过库函数实现的,后面会具体讲解)
**************************************************************************************************/

/*=============================================================================
* 位绑定公式:
* 1、SRAM区域 :0X2200 0000 ----0X200F FFFF
*    Aliasaddr = 0X22000000 + ( A -0X20000000 )*32 + n*4
* 2、片上外设区域 :0X4200 0000 ----0X400F FFFF
*    Aliasaddr = 0X42000000 + ( A -0X40000000 )*32 + n*4
* 参数解释:
*          Aliasaddr : 设置“端口GPIOx的第n位”的寄存器_相应位的实际地址
*          A : 端口GPIOx的基地址(GPIOx_BASE) + 相应寄存器的偏移地址
*          n : 配置的是相应寄存器的第n位
* 寄存器的偏移地址 :CRL  CRH  IDR  ODR  BSRR  BRR  LCKR
*                    00H  04H  08H  0CH  10H   14H  18H
=============================================================================*/

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x_lib.h"	  //包含了所有的头文件 它是唯一一个用户需要包括在自己应用中的文件,起到应用和库之间界面的作用。
#include "stm32f10x_map.h"

/******************************快速位绑定**********************************************************/
/*----------------1、宏定义要操作的寄存器地址---------------------------------------------*/
#define GPIOA_ODR (GPIOA_BASE + 0X0C)
#define GPIOA_IDR (GPIOA_BASE + 0X08)

#define GPIOB_ODR (GPIOB_BASE + 0X0C)
#define GPIOB_IDR (GPIOB_BASE + 0X08)

#define GPIOC_ODR (GPIOC_BASE + 0X0C)
#define GPIOC_IDR (GPIOC_BASE + 0X08)

#define GPIOD_ODR (GPIOD_BASE + 0X0C)
#define GPIOD_IDR (GPIOD_BASE + 0X08)

#define GPIOE_ODR (GPIOE_BASE + 0X0C)
#define GPIOE_IDR (GPIOE_BASE + 0X08)

/*----------------2、获取端口GPIOx(A-E)的对应寄存器的某一操作位的位地址-------------------*/
// #define BitBand(Addr , BitNum) *( (volatile unsigned long *)(Addr & 0xf0000000) + 0x2000000 + ((Addr&0xfffff)*32) + (BitNum*4) )
// 因为 左移、右移 语句的执行速度比乘除法语句的运动速度快,所以将上述语句改成如下方式
#define BitBand(Addr , BitNum) *( (volatile unsigned long *)( (Addr & 0xf0000000) + 0x2000000 + ((Addr&0xfffff)<<5) + (BitNum<<2) ) )

/*----------------3、宏定义函数,对固定的位绑定 进行功能封装------------------------------*/
#define PAout(n) BitBand(GPIOA_ODR , n)
#define PAin(n)  BitBand(GPIOA_IDR , n)

#define PBout(n) BitBand(GPIOB_ODR , n)
#define PBin(n)  BitBand(GPIOB_IDR , n)

#define PCout(n) BitBand(GPIOC_ODR , n)
#define PCin(n)  BitBand(GPIOC_IDR , n)

#define PDout(n) BitBand(GPIOD_ODR , n)
#define PDin(n)  BitBand(GPIOD_IDR , n)

#define PEout(n) BitBand(GPIOE_ODR , n)
#define PEin(n)  BitBand(GPIOE_IDR , n)

/*----------------函数声明部分---------------*/
void delay1ms(int t) ;
void RCC_Configuration(void) ;
void GPIO_Configuration(void) ;

/* Private functions -----------------------------------------------------------------------------*/
/**************************************************************************************************
* Function Name  : main
* Description    : 从GPIOA.8-.16输入一个电平信号,GPIOA.0-.7口分别将对应引脚输入的电平信号输出
* Input          : None
* Output         : None
* Return         : None
****************************************************************************************************/
int main(void)
{

float Div; 	//计算波特率时公式里面的除数
u16 M,F;    //临时存储Div的整数部分的数字和小数部分的数字
u32 Bound,BRR;	//Bound:要设置的波特率 , BRR:是Div的整数部分和小数部分整合后存入寄存器USART1->BRR中的值
u8  data='A';   //存放要发送的数据

RCC_Configuration(); //配置开启系统时钟
GPIO_Configuration();  //配置IO口

/*--------USART1模块的设置:UE位使能、M位来定义字长、停止位的位数、TE位、BRR寄存器选择要求的波特率----------------*/
USART1->CR1 |= (1<<13);	 //位于寄存器CR1的第13位。UE = 1 ;对USART1进行使能。(=0时,分频器和输出被禁止)
USART1->CR1 &= ~(1<<12);  //位于寄存器CR1的第12位。M = 0 ;无奇偶校验位,起始位+8位数据+停止位(=1时,带一位奇偶校验位)
USART1->CR2 &= ~(3<<12);  //位于寄存器CR2的第13-12位。STOP = 00 ;1位停止位。(=01;0.5位。 =10;2位。 =11;1.5位)
USART1->CR1 |= (1<<3);	  //位于寄存器CR1的第3位。USART1的发送使能位。TE = 1 ;发送使能(=0时,禁止发送)

Bound = 9600; //设置波特率
Div = (float)(72*1000*1000)/(Bound*16);	  //乘以16是因为该芯片是16位的。(寄存器也是16位的)
M = Div;
F = (Div-M)*16;
BRR = M<<4|F;
USART1->BRR = BRR;

/*--------发送一串字符‘A’--‘Z’到USART1的DR-----------------------------------------------------------------------------*/
for(F=0;F<26;F++)
{
USART1->DR = data;
data++;
while((USART1->SR & (1<<6))==0) ;
}

}

/*******************************************************************************
* Function Name  : Delay_Ms
* Description    : delay 1 ms.
* Input          : dly (ms)
* Output         : None
* Return         : None
*******************************************************************************/
void delay1ms(int t)
{
//机器周期T = 1/(72000000/12)s = 1/6000000 s = 1/6 us
int temp = 6000/4 ;
while(t--)
{
while(temp--)
{ ; }
}

}

/*******************************************************************************
* Function Name  : RCC_Configuration
* Description    : Configures the different system clocks.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void RCC_Configuration(void)
{
//----------使用外部RC晶振-----------
RCC_DeInit();			//初始化为缺省值
RCC_HSEConfig(RCC_HSE_ON);	//使能外部的高速时钟
while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);	//等待外部高速时钟使能就绪

//FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);	//Enable Prefetch Buffer
//FLASH_SetLatency(FLASH_Latency_2);		//Flash 2 wait state

RCC_HCLKConfig(RCC_SYSCLK_Div1);		//HCLK = SYSCLK
RCC_PCLK2Config(RCC_HCLK_Div1);			//PCLK2 =  HCLK
RCC_PCLK1Config(RCC_HCLK_Div2);			//PCLK1 = HCLK/2
RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);	//PLLCLK = 8MHZ * 9 =72MHZ
RCC_PLLCmd(ENABLE);			//Enable PLLCLK

while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);	//Wait till PLLCLK is ready
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);	//Select PLL as system clock
while(RCC_GetSYSCLKSource()!=0x08);		//Wait till PLL is used as system clock source

//---------打开相应外设时钟--------------------
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);	//使能APB2外设的GPIOA的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);	//使能APB2外设的GPIOC的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

//GPIO_PinRemapConfig(GPIO_Remap_USART1,ENABLE);

}

/*******************************************************************************
* Function Name  : GPIO_Configuration
* Description    : 初始化GPIO外设
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

/* Configure USARTx_Tx as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);

/* Configure USARTx_Rx as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);

}

程序运行前的仿真界面:



程序运行后的仿真界面:



2、串行通信
软件仿真STM32通过串口USART1发送26个英文字母(调用库函数)

首先:在主函数部分先要(调用自己编写的函数)对USART要用到的I/O端口进行配置、打开系统时钟配置和对USART1进行参数配置



下图是通过调用库函数对USART1的参数进行配置,将其配置成异步收发模式、波特率用户可以自定的串口:



源程序:

/**************************************************************************************************
*	硬件平台:STM32F103VC
*	学习重点:调用库函数来实现对USART的操作
*	实现功能:软件仿真,实现STM32通过USART1发送数据
*	作    者:赵小龙
**************************************************************************************************/

/* Includes ------------------------------------------------------------------*/
#include "stm32f10x_lib.h"	  //包含了所有的头文件 它是唯一一个用户需要包括在自己应用中的文件,起到应用和库之间界面的作用。
#include "stm32f10x_map.h"

/*----------------函数声明部分---------------*/
void delay1ms(int t) ;
void RCC_Configuration(void) ;
void GPIO_Configuration(void) ;
void USART_Configuration(u32 BaudRate) ;

/* Private functions -----------------------------------------------------------------------------*/
/**************************************************************************************************
* Function Name  : main
* Description    : 软件仿真,从USART1发送26个大写的英文字母
* Input          : None
* Output         : None
* Return         : None
****************************************************************************************************/
int main(void)
{

u8 i,data;
/*--------配置开启系统时钟、配置USART1发送/接收使用的两个I/O口、配置USART1---------------------------------------------*/
RCC_Configuration();
GPIO_Configuration();
USART_Configuration(19600);

/*--------发送一串字符‘A’--‘Z’到USART1的DR-----------------------------------------------------------------------------*/
data='A';
for(i=0;i<26;i++)
{
USART_SendData(USART1, data) ;
data++ ;
while(USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET) ;//发送完成标志位为1时便是数据发送完毕,若为0时则应让程序等待(等待数据发送发送完成)
/*注意:这里最好不要按照以下形式书写,否则会出错,具体原因我暂且还不知道
u8 status ;
status = USART_GetFlagStatus(USART1, USART_FLAG_TC) ;  //将查看状态寄存器的函数的返回值赋值给变量status
while(status == RESET) ;
*/
}

}

/*******************************************************************************
* Function Name  : Delay_Ms
* Description    : delay 1 ms.
* Input          : dly (ms)
* Output         : None
* Return         : None
*******************************************************************************/
void delay1ms(int t)
{
//机器周期T = 1/(72000000/12)s = 1/6000000 s = 1/6 us
int temp = 6000/4 ;
while(t--)
{
while(temp--)
{ ; }
}

}

/*******************************************************************************
* Function Name  : RCC_Configuration
* Description    : Configures the different system clocks.
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void RCC_Configuration(void)
{
//----------使用外部RC晶振-----------
RCC_DeInit();			//初始化为缺省值
RCC_HSEConfig(RCC_HSE_ON);	//使能外部的高速时钟
while(RCC_GetFlagStatus(RCC_FLAG_HSERDY) == RESET);	//等待外部高速时钟使能就绪

//FLASH_PrefetchBufferCmd(FLASH_PrefetchBuffer_Enable);	//Enable Prefetch Buffer
//FLASH_SetLatency(FLASH_Latency_2);		//Flash 2 wait state

RCC_HCLKConfig(RCC_SYSCLK_Div1);		//HCLK = SYSCLK
RCC_PCLK2Config(RCC_HCLK_Div1);			//PCLK2 =  HCLK
RCC_PCLK1Config(RCC_HCLK_Div2);			//PCLK1 = HCLK/2
RCC_PLLConfig(RCC_PLLSource_HSE_Div1,RCC_PLLMul_9);	//PLLCLK = 8MHZ * 9 =72MHZ
RCC_PLLCmd(ENABLE);			//Enable PLLCLK

while(RCC_GetFlagStatus(RCC_FLAG_PLLRDY) == RESET);	//Wait till PLLCLK is ready
RCC_SYSCLKConfig(RCC_SYSCLKSource_PLLCLK);	//Select PLL as system clock
while(RCC_GetSYSCLKSource()!=0x08);		//Wait till PLL is used as system clock source

//---------打开相应外设时钟--------------------
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA,ENABLE);	//使能APB2外设的GPIOA的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOC,ENABLE);	//使能APB2外设的GPIOC的时钟
RCC_APB2PeriphClockCmd(RCC_APB2Periph_AFIO,ENABLE);
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1,ENABLE);

//GPIO_PinRemapConfig(GPIO_Remap_USART1,ENABLE);

}

/*******************************************************************************
* Function Name  : GPIO_Configuration
* Description    : 初始化GPIO外设
* Input          : None
* Output         : None
* Return         : None
*******************************************************************************/
void GPIO_Configuration(void)
{
GPIO_InitTypeDef GPIO_InitStructure;

/* Configure USARTx_Tx as alternate function push-pull */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA, &GPIO_InitStructure);

/* Configure USARTx_Rx as input floating */
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA, &GPIO_InitStructure);

}

/*******************************************************************************
* Function Name  : USART_Configuration
* Description    : 初始化串口USART1(异步收发模式)
* Input          : BaudRate (要设置的波特率)
* Output         : None
* Return         : None
*******************************************************************************/
void USART_Configuration(u32 BaudRate)
{
//1、定义一个用于初始化USART的结构体
USART_InitTypeDef USART_InitStructure;

//2、给结构体元素赋值,设置 波特率、数据帧的位数、停止位的位数、奇偶校验位、硬件流控制位、USART模式(发送、接收)
USART_InitStructure.USART_BaudRate = 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_Tx | USART_Mode_Rx;

//3、调用函数USART_Init();用上面的结构体值作为参数对USART1进行初始化
USART_Init(USART1, &USART_InitStructure);

//4、调用函数USART_Cmd();对USART1进行使能
USART_Cmd(USART1, ENABLE);

}


程序运行前:



程序运行后:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: