stm32之USART

  • 重温串口的通讯协议,我们知道要配置串口通讯,至少要设置以下几个参数:字长(一次传送的数据长度)、波特率(每秒传输的数据位数)、奇偶校验位、还有停止位。对ST库函数的使用已经上手的读者应该能猜到,在初始化串口的时候,必然有一个串口初始化结构体,这个结构体的几个成员肯定就是有来存储这些控制参数的。
  • 串口工作过程分析
    波特率控制 
    波特率,即每秒传输的二进制位数,用 b/s (bps)表示,通过对时钟的控制可以改变波特率。在配置波特率时,我们向波特比率寄存器USART_BRR写入参数,修改了串口时钟的分频值USARTDIV。USART_BRR寄存器包括两部分,分别是DIV_Mantissa(USARTDIV的整数部分)和DIVFraction(USARTDIV的小数)部分,最终,计算公式为USARTDIV=DIV_Mantissa+(DIVFraction/16)。 

    收发控制
    围绕着发送器和接收器控制部分,有好多个寄存器:CR1、CR2、CR3、SR,即USART的三个控制寄存器(Control Register)及一个状态寄存器(Status Register)。通过向寄存器写入各种控制参数,来控制发送和接收,如奇偶校验位,停止位等,还包括对USART中断的控制;串口的状态在任何时候都可以从状态寄存器中查询得到。具体的控制和状态检查,我们都是使用库函数来实现的,在此就不具体分析这些寄存器位了。




    数据存储与转移
    收发控制器根据我们的寄存器配置,对数据存储转移部分的移位寄存器进行控制。当我们需要发送数据时,内核把数据从内存(变量)写入到发送数据寄存器TDR后,发送控制器将适时地自动把数据从TDR加载到发送移位寄存器,然后通过串口线Tx,把数据一位一位地发送出去,在数据从TDR转移到移位寄存器时,会产生发送寄存器TDR已空事件TXE,当数据从移位寄存器全部发送出去时,会产生数据发送完成事件TC,这些事件可以在状态寄存器中查询到。 而接收数据则是一个逆过程,数据从串口线Rx一位一位地输入到接收移位寄存器,然后自动地转移到接收数据寄存器RDR,最后用内核指令读取到内存(变量)中。


     
  • 实验分析
    实验要求:串口收发信息。
    硬件图

    程序
    #include "stm32f10x.h"
    #include "stdio.h"
    #include "stdarg.h"
    
    void RCC_Configuration(void);
    void GPIO_Configuration(void);
    void USART_Configuration(void);
    int fputc(int ch, FILE *f);
    void USART_OUT(USART_TypeDef* USARTx, uint8_t *Data,...);
    char *itoa(int value, char *string, int radix);
    
    int main()
    {
    		u16 i = 0;
    		RCC_Configuration();
    		GPIO_Configuration();
    		USART_Configuration();
    		
    		printf("\r\nWelcome!\r\n");
    		printf("\r\n你好,严世富\r\n");
    		USART_OUT(USART1,"\r 好好学习,天天向上!\n");
    		while(1)
    		{
    				if(USART_GetFlagStatus(USART1 , USART_FLAG_RXNE) == SET)
    				{	
    						USART_SendData(USART1,USART_ReceiveData(USART1));
    						for(i = 0; i < 500; i++);
    				}
    		}
    	
    }
    
    void USART_OUT(USART_TypeDef* USARTx, uint8_t *Data,...){ 
    	const char *s;
        int d;
        char buf[16];
        va_list ap;
        va_start(ap, Data);
    
    	while(*Data!=0){				                          //判断是否到达字符串结束符
    		if(*Data==0x5c){									  //'\'
    			switch (*++Data){
    				case 'r':							          //回车符
    					USART_SendData(USARTx, 0x0d);	   
    
    					Data++;
    					break;
    				case 'n':							          //换行符
    					USART_SendData(USARTx, 0x0a);	
    					Data++;
    					break;
    				
    				default:
    					Data++;
    				    break;
    			}
    			
    			 
    		}
    		else if(*Data=='%'){									  //
    			switch (*++Data){				
    				case 's':										  //字符串
                    	s = va_arg(ap, const char *);
                    	for ( ; *s; s++) {
                        	USART_SendData(USARTx,*s);
    						while(USART_GetFlagStatus(USARTx, USART_FLAG_TC)==RESET);
                    	}
    					Data++;
                    	break;
                	case 'd':										  //十进制
                    	d = va_arg(ap, int);
                    	itoa(d, buf, 10);
                    	for (s = buf; *s; s++) {
                        	USART_SendData(USARTx,*s);
    						while(USART_GetFlagStatus(USARTx, USART_FLAG_TC)==RESET);
                    	}
    					Data++;
                    	break;
    				default:
    					Data++;
    				    break;
    			}		 
    		}
    		else USART_SendData(USARTx, *Data++);
    		while(USART_GetFlagStatus(USARTx, USART_FLAG_TC)==RESET);
    	}
    }
    
    
    char *itoa(int value, char *string, int radix)
    {
        int     i, d;
        int     flag = 0;
        char    *ptr = string;
    
        /* This implementation only works for decimal numbers. */
        if (radix != 10)
        {
            *ptr = 0;
            return string;
        }
    
        if (!value)
        {
            *ptr++ = 0x30;
            *ptr = 0;
            return string;
        }
    
        /* if this is a negative value insert the minus sign. */
        if (value < 0)
        {
            *ptr++ = '-';
    
            /* Make the value positive. */
            value *= -1;
        }
    
        for (i = 10000; i > 0; i /= 10)
        {
            d = value / i;
    
            if (d || flag)
            {
                *ptr++ = (char)(d + 0x30);
                value -= (d * i);
                flag = 1;
            }
        }
    
        /* Null terminate the string. */
        *ptr = 0;
    
        return string;
    
    } /* NCL_Itoa */
    
    void RCC_Configuration(void)
    {
    		RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1 | RCC_APB2Periph_GPIOA, ENABLE);
    }
    
    void GPIO_Configuration(void)
    {
    		GPIO_InitTypeDef GPIO_InitStructure;
    		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);
    	
    		GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
    		GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    		GPIO_Init(GPIOA, &GPIO_InitStructure);
    }
    
    void USART_Configuration(void)
    {
    		USART_InitTypeDef USART_InitStructure;
    	
    		USART_InitStructure.USART_BaudRate = 115200;
    		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_Cmd(USART1 , ENABLE);
    }
    
    int fputc(int ch,FILE *f)
    {
    		USART_SendData(USART1,(u8) ch);
    		while(USART_GetFlagStatus(USART1,USART_FLAG_TC) == RESET);
    		return ch;
    }
    



评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值