正点原子STM32的SYSTEM中的delay、sys.c、usart.c文件代码

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控制功能
//具体实现思想,参考<<CM3权威指南>>第五章(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

猜你喜欢

转载自blog.csdn.net/qq_39400113/article/details/111699315