STM32
直播中

往事只能回首

12年用户 553经验值
私信 关注
[问答]

SYSTEM中的delay、sys.c、usart.c文件代码分享

SYSTEM中的delay、sys.c、usart.c文件代码分享

回帖(1)

刘勇

2021-12-10 14:34:08
delay.c

#include "delay.h"


static u8  fac_us=0;                                                        //us延时倍乘数                          
static u16 fac_ms=0;                                                        //ms延时倍乘数,在ucos下,代表每个节拍的ms数                          
//初始化延迟函数
//当使用OS的时候,此函数会初始化OS的时钟节拍
//SYSTICK的时钟固定为HCLK时钟的1/8
//SYSCLK:系统时钟
void delay_init()
{


        SysTick_CLKSourceConfig(SysTick_CLKSource_HCLK_Div8);        //选择外部时钟  HCLK/8
        fac_us=SystemCoreClock/8000000;                                //为系统时钟的1/8  
        fac_ms=(u16)fac_us*1000;                                        //非OS下,代表每个ms需要的systick时钟数
}
//延时nus
//nus为要延时的us数.                                                                                      
void delay_us(u32 nus)
{               
        u32 temp;                     
        SysTick->LOAD=nus*fac_us;                                         //时间加载                           
        SysTick->VAL=0x00;                                                //清空计数器
        SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;        //开始倒数          
        do
        {
                temp=SysTick->CTRL;
        }while((temp&0x01)&&!(temp&(1<<16)));                //等待时间到达   
        SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;        //关闭计数器
        SysTick->VAL =0X00;                                               //清空计数器         
}
//延时nms
//注意nms的范围
//SysTick->LOAD为24位寄存器,所以,最大延时为:
//nms<=0xffffff*8*1000/SYSCLK
//SYSCLK单位为Hz,nms单位为ms
//对72M条件下,nms<=1864
void delay_ms(u16 nms)
{                                     
        u32 temp;                  
        SysTick->LOAD=(u32)nms*fac_ms;                                //时间加载(SysTick->LOAD为24bit)
        SysTick->VAL =0x00;                                                        //清空计数器
        SysTick->CTRL|=SysTick_CTRL_ENABLE_Msk ;        //开始倒数  
        do
        {
                temp=SysTick->CTRL;
        }while((temp&0x01)&&!(temp&(1<<16)));                //等待时间到达   
        SysTick->CTRL&=~SysTick_CTRL_ENABLE_Msk;        //关闭计数器
        SysTick->VAL =0X00;                                               //清空计数器                      
}
//延时 S
//最大为18s
void delay_s(u8 s)
{
        delay_ms(s*100);//1
        delay_ms(s*100);//2
        delay_ms(s*100);//3
        delay_ms(s*100);//4
        delay_ms(s*100);//5
        delay_ms(s*100);//6
        delay_ms(s*100);//7
        delay_ms(s*100);//8
        delay_ms(s*100);//9
        delay_ms(s*100);//10
}
  delay.h

  
#ifndef __DELAY_H
#define __DELAY_H                           
#include "sys.h"  
         
void delay_init(void);
void delay_ms(u16 nms);
void delay_us(u32 nus);
void delay_s(u8 s);
#endif
sys.c

  #include "sys.h"    sys.h


#ifndef __SYS_H
#define __SYS_H       
#include "stm32f10x.h"                                                                                                                                            
         
//位带操作,实现51类似的GPIO控制功能
//具体实现思想,参考<>第五章(87页~92页).
//IO口操作宏定义
#define BITBAND(addr, bitnum) ((addr & 0xF0000000)+0x2000000+((addr &0xFFFFF)<<5)+(bitnum<<2))
#define MEM_ADDR(addr)  *((volatile unsigned long  *)(addr))
#define BIT_ADDR(addr, bitnum)   MEM_ADDR(BITBAND(addr, bitnum))
//IO口地址映射
#define GPIOA_ODR_Addr    (GPIOA_BASE+12) //0x4001080C
#define GPIOB_ODR_Addr    (GPIOB_BASE+12) //0x40010C0C
#define GPIOC_ODR_Addr    (GPIOC_BASE+12) //0x4001100C
#define GPIOD_ODR_Addr    (GPIOD_BASE+12) //0x4001140C
#define GPIOE_ODR_Addr    (GPIOE_BASE+12) //0x4001180C
#define GPIOF_ODR_Addr    (GPIOF_BASE+12) //0x40011A0C   
#define GPIOG_ODR_Addr    (GPIOG_BASE+12) //0x40011E0C   


#define GPIOA_IDR_Addr    (GPIOA_BASE+8) //0x40010808
#define GPIOB_IDR_Addr    (GPIOB_BASE+8) //0x40010C08
#define GPIOC_IDR_Addr    (GPIOC_BASE+8) //0x40011008
#define GPIOD_IDR_Addr    (GPIOD_BASE+8) //0x40011408
#define GPIOE_IDR_Addr    (GPIOE_BASE+8) //0x40011808
#define GPIOF_IDR_Addr    (GPIOF_BASE+8) //0x40011A08
#define GPIOG_IDR_Addr    (GPIOG_BASE+8) //0x40011E08

//IO口操作,只对单一的IO口!
//确保n的值小于16!
#define PAout(n)   BIT_ADDR(GPIOA_ODR_Addr,n)  //输出
#define PAin(n)    BIT_ADDR(GPIOA_IDR_Addr,n)  //输入


#define PBout(n)   BIT_ADDR(GPIOB_ODR_Addr,n)  //输出
#define PBin(n)    BIT_ADDR(GPIOB_IDR_Addr,n)  //输入


#define PCout(n)   BIT_ADDR(GPIOC_ODR_Addr,n)  //输出
#define PCin(n)    BIT_ADDR(GPIOC_IDR_Addr,n)  //输入


#define PDout(n)   BIT_ADDR(GPIOD_ODR_Addr,n)  //输出
#define PDin(n)    BIT_ADDR(GPIOD_IDR_Addr,n)  //输入


#define PEout(n)   BIT_ADDR(GPIOE_ODR_Addr,n)  //输出
#define PEin(n)    BIT_ADDR(GPIOE_IDR_Addr,n)  //输入


#define PFout(n)   BIT_ADDR(GPIOF_ODR_Addr,n)  //输出
#define PFin(n)    BIT_ADDR(GPIOF_IDR_Addr,n)  //输入


#define PGout(n)   BIT_ADDR(GPIOG_ODR_Addr,n)  //输出
#define PGin(n)    BIT_ADDR(GPIOG_IDR_Addr,n)  //输入


#endif
usart.c


#include "sys.h"
#include "usart.h"


/*
当串口不发送数据时TC标志位为0。当TC(发送完成),该位被置位为1,
表示 USART_DR内的数据已经被发送完成了。如果设置了这个位的中断,
则会产生中断。该位也有两种清零方式:
1)读 USART_SR,写USART_DR。
2)直接向该位写 0。
*/
//重定向c库函数printf到串口,重定向后可使用printf函数
int fputc(int ch, FILE *f)
{
        //发送一个字节数据到串口
        USART_SendData(USART1, (uint8_t) ch);//等价于 USART1->DR = (u8) ch;               
        //循环发送,直到发送完毕。while (0);跳出循环,while(1);代码不再向下执行
        while (USART_GetFlagStatus(USART1, USART_FLAG_TC) == RESET);//等价于while((USART1->SR&0X40)==0);
        return (ch);
}


void uart_init(u32 bound)
{
    //GPIO端口设置
        GPIO_InitTypeDef GPIO_InitStructure;
        USART_InitTypeDef USART_InitStructure;
        NVIC_InitTypeDef NVIC_InitStructure;


        RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE);//使能USART1时钟
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);//使能GPIOA时钟
       
        //USART1_TX   GPIOA.9
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9; //PA.9
        GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;        //复用推挽输出
        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.9


        //USART1_RX          GPIOA.10初始化
        GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;//PA10
        GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;//浮空输入
        GPIO_Init(GPIOA, &GPIO_InitStructure);//初始化GPIOA.10  


        //Usart1 NVIC 配置
        NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;
        NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=1;//抢占优先级3
        NVIC_InitStructure.NVIC_IRQChannelSubPriority = 1;                //子优先级3
        NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;                        //IRQ通道使能
        NVIC_Init(&NVIC_InitStructure);        //根据指定的参数初始化VIC寄存器


        //USART 初始化设置
        USART_InitStructure.USART_BaudRate = bound;//串口波特率
        USART_InitStructure.USART_WordLength = USART_WordLength_8b;//字长为8位数据格式
        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); //初始化串口1
       
        USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启串口接收中断
        USART_Cmd(USART1, ENABLE); //使能串口1


}
/*RXNE(读数据寄存器非空),默认情况下也就是没有数据接收时,该寄存器值为0
当有数据被接收到时,该位会被自动置1,就可以读出来了。这时候我们要做的就
是尽快去读取USART_DR,通过读USART_DR可以将该位清零,也可以向该位写0,直接清除。*/       
//一个汉字是2个字节,一个英文字母(不分大小写)是一个字节,中文标点占三个字节, 英文标点占一个字节.
u8 USART_RX_BUF[USART_REC_LEN];//接收缓冲,最大USART_REC_LEN个字节.
u16 USART_RX_STA=0;//接收状态标记       
/*
当接收到从电脑发过来的数据,把接收到的数据保存在 USART_RX_BUF 中,同时在
接收状态寄存器(USART_RX_STA)中计数接收到的有效数据个数,当收到回车(回车的
表示由 2 个字节组成:0X0D 和 0X0A)的第一个字节 0X0D 时,计数器将不再增加,等待
0X0A 的到来,而如果 0X0A 没有来到,则认为这次接收失败,重新开始下一次接收。如
果顺利接收到 0X0A,则标记 USART_RX_STA 的第 15 位,这样完成一次接收,并等待该
位被其他程序清除,从而开始下一次的接收,而如果迟迟没有收到 0X0D,那么在接收数
据超过 USART_REC_LEN 的时候,则会丢弃前面的数据,重新接收。
—————————————————————————————————————————————————————————————————
|                                                USART_RX_STA
—————————————————————————————————————————————————————————————————
|                bit15           |                bit14                  |                bit13~0                         |
—————————————————————————————————————————————————————————————————
|        接收完成标志        |        接收到0x0D标志        |        接收到有效数据的个数|
—————————————————————————————————————————————————————————————————
*/
void USART1_IRQHandler(void) //串口1中断服务程序
        {
        u8 ucTemp;
        if(USART_GetITStatus(USART1, USART_IT_RXNE)!= RESET) //如果发生了接收中断RXNE会自动置位为1  (接收到的数据必须是0x0d 0x0a结尾)
        {
                ucTemp =USART_ReceiveData(USART1);//读取接收到的数据               
                if((USART_RX_STA&0x8000)==0)//接收未完成(每次进入中断服务函数都要判断bit15接收完成标志位是否置位为1)
                {
                        if(USART_RX_STA&0x4000)//接收到了回车符,也就是0x0D (如果bit15接收完成标志位未置位为1,就要判断是否接收到了回车符的第一个字节。USART_RX_STA是0还是1)
                        {
                                if(ucTemp!=0x0A)//没有接收到回车符的第二个字节0x0A(在确定接收到0x0d后要判断是否接受到了0x0a,才能确定接收正确)
                                        USART_RX_STA=0;//接收错误,重新开始
                                else
                                        USART_RX_STA|=0x8000;//接收完成了(或运算是用来置位的,接收到0x0d也就收到了0x0a说明接收正确接收完成,把bit15接收完成标志位置1)
                        }
                        else //没有接收到了回车符,也就是没有收到0x0D,中断来了继续接收数据
                        {       
                                if(ucTemp==0x0D)//中断来了继续接收数据,也要先判断一下是否接受到了接收到回车符的第一个字节
                                        USART_RX_STA|=0x4000;//如果接收到回车符的第一个字节0x0D,就要将接收到回车的bit14位0x0D标志位置1
                                else//中断来了继续接收数据,如果还没有接收到回车符的第一个字节,就要把接收到的数据存到缓冲区USART_RX_BUF[]
                                {
                                        USART_RX_BUF[USART_RX_STA&0X3FFF]=ucTemp;//把寄存器USART_RX_STA的bit13~0做清零处理,用来存放接收到的数据ucTemp
                                        USART_RX_STA++;//每次接收到一个新数据就要把USART_RX_STA的值加1
                                        if(USART_RX_STA>(USART_REC_LEN-1))
                                                USART_RX_STA=0;//接收数据错误,重新开始接收
                                }                 
                        }
                }                    
     }
}
  usart.h

#ifndef __USART_H
#define __USART_H
#include "stdio.h"       
#include "sys.h"


#define USART_REC_LEN                          200          //定义最大接收字节数 200                 
extern u8  USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u16 USART_RX_STA;                         //接收状态标记                         
void uart_init(u32 bound);


#endif
举报

更多回帖

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