找回密码
 立即注册

QQ登录

只需一步,快速开始

搜索
查看: 2675|回复: 0
打印 上一主题 下一主题
收起左侧

STM32之串口通信

[复制链接]
跳转到指定楼层
楼主
ID:107189 发表于 2016-3-4 20:13 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
实验目的:
实现利用串口1不停的打印一个信息到电脑上,同时接收从串口发过来的数据,把发送过来的数据直接送回给电脑。
实验平台:
基于STM32F103C8T6的彩屏开发板
硬件接口:
      
注意:因为我的开发板上的串口和LED共用了PA9和PA10,所以在使用USART1时务必屏蔽LED,不然两者会互相影响而导致实现现象无法呈现。
相关寄存器:
1,串口时钟使能。串口作为STM32 的一个外设,其时钟由外设时钟使能寄存器控制,这
里我们使用的串口1 是在APB2ENR 寄存器的第14 位。
2,串口复位。串口1 的复位是通过配置APB2RSTR 寄存器的第14位来实现的。。通过向该位写1来复位串口1,写0 结束复位。
3,串口波特率设置。每个串口都有一个自己独立的波特率寄存器USART_BRR
波特率的计算,STM32 的串口波特率计算公式如下:
                       
上式中, 是给串口的时钟(PCLK1 用于USART2、3、4、5,PCLK2 用于USART1);USARTDIV是一个无符号定点数。我们只要得到USARTDIV 的值,就可以得到串口波特率寄存器USART1->BRR的值。
4,串口控制。STM32 的每个串口都有3 个控制寄存器USART_CR1~3,串口的很多配置
都是通过这3 个寄存器来设置的
5,数据发送与接收。STM32 的发送与接收是通过数据寄存器USART_DR 来实现的,这是
一个双寄存器,包含了TDR 和RDR。
6,串口状态。串口的状态可以通过状态寄存器USART_SR 读取。
(注:详细的介绍使用请参考ST公司的数据手册)
程序设计:
(注:本人的usart.c usart.h delay.cdelay.h sys.c sys.h是引用网上一位网友整理的)
    usart.h
#ifndef __USART_H
#define __USART_H
#include<stm32f10x_lib.h>
#include"stdio.h"   
extern u8USART_RX_BUF[64];    //接收缓冲,最大63个字节.末字节为换行符
extern u8USART_RX_STA;        //接收状态标记   
//如果想串口中断接收,请不要注释以下宏定义
#define EN_USART1_RX //使能串口1接收
void uart_init(u32 pclk2,u32 bound);
#endif     
    usart.c
#include "sys.h"
#include "usart.h"
//加入以下代码,支持printf函数,而不需要选择useMicroLIB   
#if 1
#pragmaimport(__use_no_semihosting)            
//标准库需要的支持函数               
struct __FILE
{
  int handle;
};
FILE__stdout;      
//定义_sys_exit()以避免使用半主机模式   
_sys_exit(int x)
{
  x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{     
while((USART1->SR&0X40)==0);//循环发送,直到发送完毕  
  USART1->DR = (u8)ch;     
  return ch;
}
#endif
//end
//////////////////////////////////////////////////////////////////
#ifdefEN_USART1_RX   //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误   
u8USART_RX_BUF[64];    //接收缓冲,最大64个字节.
//接收状态
//bit7,接收完成标志
//bit6,接收到0x0d
//bit5~0,接收到的有效字节数目
u8USART_RX_STA=0;      //接收状态标记   
void USART1_IRQHandler(void)
{
  u8 res;   
if(USART1->SR&(1<<5))//接收到数据
{  
     res=USART1->DR;
     if((USART_RX_STA&0x80)==0)//接收未完成
     {
         if(USART_RX_STA&0x40)//接收到了0x0d
         {
             if(res!=0x0a)
                 USART_RX_STA=0;//接收错误,重新开始
             else
                 USART_RX_STA|=0x80; //接收完成了
         }else //还没收到0X0D
         {  
             if(res==0x0d)
                 USART_RX_STA|=0x40;
             else
             {
                 USART_RX_BUF[USART_RX_STA&0X3F]=res;
                 USART_RX_STA++;
                 if(USART_RX_STA>63)USART_RX_STA=0;//接收数据错误,重新开始接收   
             }      
         }
     }                                             
  }                                          
}
#endif
//该函数的重点就是判断接收是否完成,通过检测是否收到0X0D、0X0A 的连续2 个字节//(0X0D 后跟0X0A表示回车键)来检测是否结束。当检测到这个结束序列之后,就会置//位USART_RX_STA的最高为来标记已经收到了一次数据。之后等待外部函数清空该位//之后才开始第二次接收。所接收的数据全部存放在USART_RX_BUF里面,一次接收数//据不能超过64个字节,否则被丢弃。                                   
//初始化IO 串口1
//pclk2:PCLK2时钟频率(Mhz)
//bound:波特率
//CHECK OK
//091209
void uart_init(u32 pclk2,u32 bound)
{     
  float temp;
  u16 mantissa;
  u16fraction;   
temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV
mantissa=temp;             //得到整数部分
  fraction=(temp-mantissa)*16;//得到小数部分
   mantissa<<=4;
  mantissa+=fraction;
RCC->APB2ENR|=1<<2;  //使能PORTA口时钟
RCC->APB2ENR|=1<<14; //使能串口时钟
GPIOA->CRH&=0XFFFFF00F;
GPIOA->CRH|=0X000008B0;//IO状态设置
      
RCC->APB2RSTR|=1<<14;  //复位串口1
RCC->APB2RSTR&=~(1<<14);//停止复位      
  //波特率设置
USART1->BRR=mantissa; // 波特率设置
USART1->CR1|=0X200C; //1位停止,无校验位.
#ifdefEN_USART1_RX        //如果使能了接收
  //使能接收中断
USART1->CR1|=1<<8;   //PE中断使能
USART1->CR1|=1<<5;   //接收缓冲区非空中断使能      
MY_NVIC_Init(3,3,USART1_IRQChannel,2);//组2,最低优先级
#endif
}
  主函数
#include<stm32f10x_lib.h>
#include"common.h"   
int main(void)
{        
  u8 t;
  u8 len;
  u16times=0;
  Stm32_Clock_Init(9);//系统时钟设置
  delay_init(72);    //延时初始化
  uart_init(72,9600);//串口初始化为9600
  while(1)
  {
     if(USART_RX_STA&0x80)
     {                    
         len=USART_RX_STA&0x3f;//得到此次接收到的数据长度
         printf("\n您发送的消息为:\n");
         for(t=0;t<len;t++)
         {
             USART1->DR=USART_RX_BUF[t];
             while((USART1->SR&0X40)==0);//等待发送结束
         }
         printf("\n\n");//插入换行
         USART_RX_STA=0;
     }else
     {
         times++;
         if(timesP00==0)
         {
             printf("\n 简单的串口实验\n");
         }
         if(times 0==0)printf("请输入数据,以回车键结束\n");
         delay_ms(10);  
     }
}  
}
实验现象:



分享到:  QQ好友和群QQ好友和群 QQ空间QQ空间 腾讯微博腾讯微博 腾讯朋友腾讯朋友
收藏收藏 分享淘帖 顶 踩
回复

使用道具 举报

您需要登录后才可以回帖 登录 | 立即注册

本版积分规则

小黑屋|51黑电子论坛 |51黑电子论坛6群 QQ 管理员QQ:125739409;技术交流QQ群281945664

Powered by 单片机教程网

快速回复 返回顶部 返回列表