历史上的今天
返回首页

历史上的今天

今天是:2024年12月17日(星期二)

正在发生

2018年12月17日 | STM32 串行通信 USART 程序例举

2018-12-17 来源:eefocus

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);

 

}

 

程序运行前:




程序运行后:






推荐阅读

史海拾趣

CIPS公司的发展小趣事

自CIPS系统上线以来,其业务量呈现快速增长的态势。通过CIPS系统处理的跨境人民币业务量逐年攀升,连接到该系统的参与者数量也大幅增加。这些参与者遍布全球各地,涵盖了银行、金融机构等多个领域。CIPS系统的业务范围不断扩大,实际业务覆盖全球多个国家和地区,为全球金融网络的发展做出了重要贡献。

Diconex公司的发展小趣事

品质是电子行业的生命线。Diconex公司深知品质的重要性,因此从原材料采购到生产制造的每一个环节都严格把控品质。公司建立了完善的质量管理体系,对每一道生产工序都进行严格的检测和评估。这种对品质的执着追求使得Diconex的产品在市场上具有很高的口碑和竞争力。

Antenna Factor公司的发展小趣事

Antenna Factor公司始终注重产品质量和客户体验。他们建立了严格的质量管理体系,从原材料采购到产品生产的每一个环节都进行严格的把控。同时,公司还加强了对售后服务的管理和改进,确保客户在使用过程中能够得到及时、有效的支持。这些举措使得Antenna Factor公司的产品质量和品牌形象得到了显著提升。

CEVA, Inc公司的发展小趣事

随着万物互联时代的到来,CEVA公司迎来了新的发展机遇。Wi-Fi 6、Wi-Fi 7、5G-Advanced和蜂窝式物联网等技术的快速发展,推动了客户对新建置芯片和解决方案的需求。CEVA凭借其在无线连接和智能传感技术领域的领先地位,能够为客户提供全面的解决方案,满足这些技术在多个终端市场带来的巨大商机。同时,CEVA也是唯一能够提供蓝牙加上Wi-Fi或UWB加上蓝牙等组合解决方案的授权许可商,这一优势使得CEVA在全球半导体产业中占据了重要地位。

以上是基于公开资料对CEVA, Inc.在电子行业中的几个重要发展节点的概述。这些故事展示了CEVA如何在技术创新、市场布局和应对挑战等方面取得了显著成就,为公司的持续发展奠定了坚实基础。然而,由于电子行业的快速发展和不断变化的市场环境,CEVA的未来仍充满挑战和机遇。

德国ACAM公司的发展小趣事

2023年,ACAM公司与上海科技大学智造系统工程中心(CASE)签署了增材制造联合研发、应用研究和教育培训协议。这次合作标志着ACAM公司在增材制造领域的布局进一步深化,双方将共同推动增材制造技术的创新和应用,为行业的发展贡献更多的力量。

这五个故事展示了德国ACAM公司在电子行业中的发展历程和取得的成就。从创立之初的技术突破,到被收购后的技术实力大增,再到超声波计量领域的革命性突破,以及与高校合作推动增材制造发展,ACAM公司始终保持着创新的精神和不断进取的态度,为电子行业的发展做出了重要贡献。

Delkin Devices公司的发展小趣事

Delkin Devices公司成立于1986年,总部设在美国加利福尼亚州的圣迭戈市。公司由一群富有远见和创造力的工程师和企业家创立,他们看到了未来数据存储技术的巨大潜力。在创立初期,Delkin Devices专注于研发和生产高质量的闪存存储设备,以满足当时市场对数据存储不断增长的需求。通过不断的技术创新和优质的客户服务,Delkin Devices逐渐在电子行业中崭露头角。

问答坊 | AI 解惑

wince c# 画图问题

系统:wince 5.0 开发工具: vs C# 2008 SDK :.net compact framework 3.5 问题描述:              开始在windows xp 执行这段代码没有问题,能画图:          &nb ...…

查看全部问答>

一个划时代的伟大产品-超级硬件调试器横空出世

一个划时代的伟大产品-超级硬件调试器横空出世     程序员中多年来一直流传着一种传说,除了市面上能够见到的为数不多的几种调试软件之外,还存在着一种神秘的硬件调试器,其功能强大无比。任何调试软件调不了的程序,硬件调试器都能搞 ...…

查看全部问答>

螺旋

哪位大侠知道怎么样把一张背景图采用螺旋方式显示吗?就是顺时针扇形方式来显示 给人动态效果,而不是一次性把图片显示出来!…

查看全部问答>

PIC16单片机的C编译起哪儿下载?如何与MAPLAB一起使用?

找了很长时间,网上都没有PIC16单片机得C编译器(很多都是DEMO)。还有,如果有了这个单片机,如何在MAPLAB中使用这个编译器?…

查看全部问答>

f2812 SCI RS485 调试

1.最近我用sci调试RS485的时候遇到一个怪现象: 有时候(不是全部,重新加载程序的时候一般都是)cpu明明有数据发出来,SCIRX,SCITX波形正常,可是485驱动芯片出来的两线信号发不出来,示波器只能看到负半波.只要我把与其通信的人机界面的通讯口拔出来 ...…

查看全部问答>

有关51单片机低频频率计的问题

我想问一下低频频率计用C语言编写,一秒种是如何采集3次信号的 用测周期法测量.…

查看全部问答>

LM3S811库函数使用

IntEnable()里面的参数是什么 怎么用的   手册上好像没说…

查看全部问答>

【汇总】德仪MSP430视频

MSP430Ware 入门介绍较以往其他版本,德州仪器 IDE CCS V5.1 程序更加简练有效,运行更加快捷,开发环境也更加直观。这里将着重介绍CCS v5.1一个新的组成部份- TI资源管理器(TI Resource Explorer)。TI资源管理器向客户提供一种直接简单的途径进 ...…

查看全部问答>

STM32-FSMC-LCD详解

/*来源于网络非原创*/ STM32-FSMC-LCD详解LCD有如下控制线: CS:Chip Select 片选,低电平有效 RS:Register Select 寄存器选择 WR:Write 写信号,低电平有效 RD:Read 读信号,低电平有效 RESET:重启信号,低电平有效 DB0-DB15:数据线 ...…

查看全部问答>

关于AMC7135的12V三串纠错分享

最近车上的前阅读灯坏了,想用LED代替,又省电又明亮。 网上找了下关于AMC7135的电路,在计算供电电阻的时候发现一个小错误,分享出来免得大家碰到的时候浪费时间。 百度文库找了个文档,链接就不发了,百度一下很多的。这个是12V串三个的线路 ...…

查看全部问答>