STM32 串口 通信 中断

一、数据发送与接收。
(1)、STM32 的发送与接收是通过数据寄存器 USART_DR 来实现的,这是一个双寄存器,包含了 TDR 和 RDR。
当向该寄存器写数据的时候,串口就会自动发送;
当收到数据的时候,也是存在该寄存器内。
1)STM32 库函数操作 USART_DR 寄存器发送数据的函数是:
void USART_SendData(USART_TypeDef* USARTx, uint16_t Data);通过该函数向串口寄存器 USART_DR 写入一个数据。
2)STM32 库函数操作 USART_DR 寄存器读取串口接收到的数据的函数是:
uint16_t USART_ReceiveData(USART_TypeDef* USARTx);通过该函数可以读取串口接受到的数据。

(2)、获取相应 串口状态,串口的状态可以通过状态寄存器 USART_SR 读取。
1)在我们固件库函数里面,读取串口状态的函数是:
FlagStatus USART_GetFlagStatus(USART_TypeDef* USARTx, uint16_t USART_FLAG);
这个函数的第二个入口参数非常关键,它是标示我们要查看串口的哪种状态,比如上面讲解的RXNE(读数据寄存器非空)以及 TC(发送完成)。
例如:
【1】我们要判断读寄存器是否非空(RXNE),操作库函数的方法是:
USART_GetFlagStatus(USART1, USART_FLAG_RXNE);
【2】我们要判断发送是否完成(TC),操作库函数的方法是:
USART_GetFlagStatus(USART1, USART_FLAG_TC);
等等,这些标识号在 MDK 里面是通过宏定义定义的。

(3)、获取相应 中断状态 (注意区别(2)和(3))

1)当我们使能了某个中断的时候,当该中断发生了,就会设置状态寄存器中的某个标志位。经常我们在中断处理函数中,要判断该中断是哪种中断,使用的函数是:
ITStatus USART_GetITStatus(USART_TypeDef* USARTx, uint16_t USART_IT)
比如我们使能了串口发送完成中断,那么当中断发生了, 我们便可以在中断处理函数中调用这个函数来判断到底是否是串口发送完成中断。
【1】方法是:USART_GetITStatus(USART1, USART_IT_TC)
返回值是 SET,说明是串口发送完成中断发生。

2)这里要注意区分的是中断的不同种类:
有:【1】串口中断 {void uart2_init(u32 bound)、void USART2_IRQHandler(void)};
【2】外部中断 {void EXTIX_Init(void)、void EXT10_IRQHandler(void)}
【3】 定时器中断

(4)串口配置的一般步骤:

  1. 串口时钟 和 GPIO时钟 使能{RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);
    到底什么时候用APB1,什么时候用APB2,到 stm32f10x.h 里找匹配 }

  2. GPIO端口模式的设置 {包括:GPIO_Pin、GPIO_Mode 、GPIO_Speed}

  3. 串口设置 {包括:1)串口复位(这一步不是必须的,省略了);
    2)串口参数初始化(主要注意:USART_BaudRate、 USART_Mode、 USART_ITConfig);
    3)串口使能}

  4. 开启中断,初始化NVIC{需要中断,才要这一步}

  5. 编写中断处理函数{即: void USART2_IRQHandler(void) };

  6. 编写串口数据收发函数{即:void ult_receive() }

注意:对于复用功能的GPIO,要先使能GPIO时钟,同时设置GPIO模式为 复用功能对应的模式。

二、程序编写

int main(void)
 {	
	 
   NVIC_PriorityGroupConfig(NVIC_PriorityGroup_2);   
   uart2_init(115200);      //串口通信时的波特率设置(可以用串口助手来测试具体是多少)
	 while(1)
		{ 
		      ult_receive();
	  }
 }
//对串口2进行初始化
void uart2_init(u32 bound){	 
    GPIO_InitTypeDef GPIO_InitStructure;
	USART_InitTypeDef USART_InitStructure;
	NVIC_InitTypeDef NVIC_InitStructure;
	
	 //到底什么时候用APB1,什么时候用APB2,到 stm32f10x.h 里找匹配
	 //GPIOx、ADCx、TIMx、USARTx 的时钟来源都不同
	RCC_APB1PeriphClockCmd(RCC_APB1Periph_USART2, ENABLE);	
    RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA, ENABLE);	
    
	    //USART2_TX   GPIOA.2
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_2; 
    GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;	
    GPIO_Init(GPIOA, &GPIO_InitStructure);   
        //USART2_RX	  GPIOA.3
    GPIO_InitStructure.GPIO_Pin = GPIO_Pin_3;//PA3
	GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
    GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
    GPIO_Init(GPIOA, &GPIO_InitStructure);

       //USART 参数初始化
	USART_InitStructure.USART_BaudRate = bound;
	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(USART2, &USART_InitStructure);      //初始化串口
    USART_Cmd(USART2, ENABLE);         //使能串口 
   
      //这个函数的第二个入口参数是标示使能串口的类型,也就是使能哪种中断,因为串口的中断类型有很多种。  
      //USART_ITConfig(USART2, USART_IT_IDLE, ENABLE);
      //USART_ITConfig(USART1,USART_IT_TC,ENABLE); //发送数据结束的时候(TC,发送完成)产生中断
    USART_ITConfig(USART2, USART_IT_RXNE, ENABLE);  //开启接收中断,接收到数据中断
         
      //Usart2 NVIC设置
    NVIC_InitStructure.NVIC_IRQChannel =USART2_IRQn;  //正确选择 第几号串口
	NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority=3 ;
	NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;		
	NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;		
	NVIC_Init(&NVIC_InitStructure);  
}

//void USART2_IRQHandler(void)函数是串口 1 的中断响应函数,当串口 1 发生了相应的中断后,就会跳到该函数执行。
//串口中断服务程序,这一段是 接收数据服务
void USART2_IRQHandler(void){
		if(USART_GetITStatus(USART2, USART_IT_RXNE) != RESET){    //判断 接收中断				
			Res2 =USART_ReceiveData(USART2);	
			if(USART2_RX_STA==0){   //  USART2_RX_STA 是接收状态标记,0 代表未接收完成					
					UART2_DATA[RxCounter++]=Res2 ;					
					if(RxCounter > GET_REC_LEN){	
							USART2_RX_STA  = 1;   //接收完成了
							RxCounter = 0;
					}
			}
   	    }
	
} 
 

//串口数据接收程序
void  ult_receive()
{	
	 if(USART2_RX_STA==1) {   // 如果接收完成了,可以复位后,接着接收;也可以先把数据发送到其它串口, 再复位这个串口,接着接收。
		RxCounter = 0;   		
		USART2_RX_STA = 0;
	 }
	 if(UART2_DATA[16]==11 && UART2_DATA[17]==7) {			
			i=0;
			Counter = USART2_REC_LEN;
			count_flag =1;
			UART2_DATA[16] = 0;
			UART2_DATA[17] = 0;	
	 }
}	

补充:串口的发送
这个地方那个之所以把这个写出来主要是想说发送中断和接受中断其实是共用一个中断函数的,到底是那个中断发生了呢,这就需要我们读取中断状态标志来识别了。

//发送数据
//使用函数USART_SendData(USART1, char data),一次只能发送一个字符。

1)当然我们可以用如下函数发送字符串。
void USART1_Puts(char * str){ 
     while(*str) { 
            USART_SendData(USART1, *str++);  //发送一个字符
            while(USART_GetFlagStatus(USART1, USART_FLAG_TXE) == RESET);  //等待发送完毕
      } 
}

2)当然我们也可以循环发送字符串数组
for(i = 0; TxBuf1 != '\0'; i++) {       // TxBuf1为定义好的字符串数组
       USART_SendData(USART2 , TxBuf1);
       while(USART_GetFlagStatus(USART2, USART_FLAG_TC)==RESET);  //等待发送完毕
}
int main(void){		
 	while(1){
		if(USART_RX_STA&0x8000){					   
			len=USART_RX_STA&0x3fff;
			
            //循环发送字符串数组  要明确的是 发送字符数组的长度
            //发送的程序可以写在 main 函数里,也可以写在 中断服务函数 里 
			for(t=0;t<len;t++){
				USART_SendData(USART1, USART_RX_BUF[t]);
				while(USART_GetFlagStatus(USART1,USART_FLAG_TC)!=SET);
			}
			
			USART_RX_STA=0;
		}
		else{
			times++;
			if(times%5000==0){
				printf("\r\nÕ½½¢STM32¿ª·¢°å ´®¿ÚʵÑé\r\n");
				printf("ÕýµãÔ­×Ó@ALIENTEK\r\n\r\n");
			}
			if(times%200==0) 
			     printf("ÇëÊäÈëÊý¾Ý,ÒԻسµ¼ü½áÊø\n");  
			if(times%30==0)
			     LED0=!LED0;
			delay_ms(10);   
		}
	}	 
 }

  • 4
    点赞
  • 25
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值