STM32 实现串口通信 寄存器版

STM32 实现串口通信 寄存器版

上篇使用的库函数 实现串口通信 ,这么我们就以寄存器实现串口通信

寄存器编写和库函数编写原理一样,不同的是需要去查找它的寄存器赋值,以及需要一步波特率计数

代码如下:


/*串口初始化*/
void Uart_Init(u32 mhz,u32 bound)
{
	float temp;
	
	u16 A,B,C;
	temp = (float) (mhz * 1000000) / (bound * 16);  //得到USARTDIV
	A = temp;    //得到整数
	B = (temp - A) * 16;   //得到小数
	A = (A << 4);
	C = A	+ B;
	
	RCC->APB2ENR |= (1 << 2);  //A9 TX A10 RX
	RCC->APB2ENR |= (1 << 14);   //使能时钟 A  USART1
	
	GPIOA->CRH &= 0xFFFFF00F;
	GPIOA->CRH |= 0x000004B0;   //原子的可以以上拉输入 8b 但普中的不行
	
	//波特率设置
	USART1->BRR = C;
	USART1->CR1 |= 0x200C; //1位停止,无校验位
	
	USART1->CR1 |= 1 << 5; //接收缓冲区非空中断使能
	
	Nvic_Init(3,2,USART1_IRQn,2);  //中断初始化
}



void USART1_IRQHandler()
{

	u8 res;
	if(USART1->SR & (1 << 5))   //是否接收数据
	{
		res = USART1->DR;
		USART1->DR = res;
		while((USART1->SR & 0x40) == 0);   //等待发送完成
	}
}

引用文件如下:


#include "Nvic.h"

void Nvic_Init(u8 PreemptionPriority,u8 SubPriority,u8 Channel,u8 Group)
{
		u32 temp;    

    u8 IPRADDR  =Channel/4;  //每组只能存4个,得到组地址 
    u8 IPROFFSET = Channel%4;//在组内的偏移
    IPROFFSET = IPROFFSET * 8 + 4;    //得到偏移的确切位置
    Nvic_PriorityGroupConfig(Group);//设置分组
    temp = PreemptionPriority << ( 4 - Group);      
    temp |= SubPriority & (0x0f >> Group);
    temp &= 0xf;//取低四位

    if(Channel<32)
			NVIC->ISER[0] |= 1 << Channel;//使能中断位(要清除的话,相反操作就OK)
    else 
			NVIC->ISER[1] |= 1 <<(Channel - 32);    
    NVIC->IP[IPRADDR] |= temp << IPROFFSET;//设置响应优先级和抢断优先级            

}

void Nvic_PriorityGroupConfig(u8 Group)
{
		u16 temp,temp1;
    temp1 = (~Group) & 0x07;//取后三位
    temp1 <<= 8;
    temp = SCB->AIRCR;  //读取先前的设置
    temp &= 0X0000F8FF; //清空先前分组
    temp |= 0X05FA0000; //写入钥匙
    temp |= temp1;       
    SCB->AIRCR = temp;  //设置分组   
}



//不能在这里执行所有外设复位!否则至少引起串口不工作.		    
//把所有时钟寄存器复位		  
void MYRCC_DeInit(void)
{	
 	RCC->APB1RSTR = 0x00000000;//复位结束			 
	RCC->APB2RSTR = 0x00000000; 
	  
  RCC->AHBENR = 0x00000014;  //睡眠模式闪存和SRAM时钟使能.其他关闭.	  
  RCC->APB2ENR = 0x00000000; //外设时钟关闭.			   
  RCC->APB1ENR = 0x00000000;   
	RCC->CR |= 0x00000001;     //使能内部高速时钟HSION	 															 
	RCC->CFGR &= 0xF8FF0000;   //复位SW[1:0],HPRE[3:0],PPRE1[2:0],PPRE2[2:0],ADCPRE[1:0],MCO[2:0]					 
	RCC->CR &= 0xFEF6FFFF;     //复位HSEON,CSSON,PLLON
	RCC->CR &= 0xFFFBFFFF;     //复位HSEBYP	   	  
	RCC->CFGR &= 0xFF80FFFF;   //复位PLLSRC, PLLXTPRE, PLLMUL[3:0] and USBPRE 
	RCC->CIR = 0x00000000;     //关闭所有中断		 

}
//系统时钟初始化函数
//pll:选择的倍频数,从2开始,最大值为16		 
void Stm32_Clock_Init(u8 PLL)
{
	unsigned char temp=0;   
	MYRCC_DeInit();		  //复位并配置向量表
 	RCC->CR|=0x00010000;  //外部高速时钟使能HSEON
	while(!(RCC->CR>>17));//等待外部时钟就绪
	RCC->CFGR=0X00000400; //APB1=DIV2;APB2=DIV1;AHB=DIV1;
	PLL-=2;				  //抵消2个单位(因为是从2开始的,设置0就是2)
	RCC->CFGR|=PLL<<18;   //设置PLL值 2~16
	RCC->CFGR|=1<<16;	  //PLLSRC ON 
	FLASH->ACR|=0x32;	  //FLASH 2个延时周期
	RCC->CR|=0x01000000;  //PLLON
	while(!(RCC->CR>>25));//等待PLL锁定
	RCC->CFGR|=0x00000002;//PLL作为系统时钟	 
	while(temp!=0x02)     //等待PLL作为系统时钟设置成功
	{   
		temp=RCC->CFGR>>2;
		temp&=0x03;
	}    
}

主函数如下:

int main()
{	
	// 10:20:20
	u8 hour = 10;
	u8 mins = 20;
	u8 sec = 59;
	
	Stm32_Clock_Init(9);   //时钟复位不能少,否则影响串口通信
	
	Delay_Init();  //SysTick初始化
	
	Uart_Init(72,9600);
	//Led_Init();
	printf ("每 隔 60s 发 送\r\n");
//	USART1->CR2 &= 00<<7;
	while(1)
	{
		if(sec == 60)
		{
			mins++;
			sec = 0;
			
			printf("\r\n当前时间 %d:%d:%d\r\n",hour,mins,sec);
		}
		if(mins == 60)
		{
			hour++;
			mins = 0;
		}
		if(hour == 24)
		{
			hour = 0;
		}
		
		Delay_s(1);
		sec++;
	//	Led_Show();
	}
}


版权声明:本文为qq_41828707原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。