STM32
直播中

陈飞

7年用户 1170经验值
私信 关注
[问答]

如何利用寄存器去实现STM3的串口通信呢

如何利用寄存器去实现STM3的串口通信呢?求解

回帖(1)

冬妮

2021-12-8 15:19:25
STM3 实现串口通信 寄存器版

上篇使用的库函数 实现串口通信 ,这么我们就以寄存器实现串口通信
寄存器编写和库函数编写原理一样,不同的是需要去查找它的寄存器赋值,以及需要一步波特率计数
代码如下:



/*串口初始化*/
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 发 送rn");
//        USART1->CR2 &= 00<<7;
        while(1)
        {
                if(sec == 60)
                {
                        mins++;
                        sec = 0;
                       
                        printf("rn当前时间 %d:%d:%drn",hour,mins,sec);
                }
                if(mins == 60)
                {
                        hour++;
                        mins = 0;
                }
                if(hour == 24)
                {
                        hour = 0;
                }
               
                Delay_s(1);
                sec++;
        //        Led_Show();
        }
}
举报

更多回帖

发帖
×
20
完善资料,
赚取积分