玩stm32也有一段时间了,对串口中断接受和DAM方式发送总一下总结,但是本节只讲述串口中断接受的基本配置,既然是基本就说明他很重要,如有疏忽,就会让串口失灵。下一节主要讲述DAM的用法。言归正传:首先我们要知道开启一个功能的步骤如下,
(1)RCC配置
(2)GPIO配置
(3)USART配置
(4)发送/接收数据
在RCC配置中,我们除了常规的时钟设置之外,需要打开USART相应的IO口时钟,USART时钟,还有管脚功能复用时钟。
1、在GPIO配置中,将发送端的管脚配置为复用推挽输出,讲接受端的管脚设置为浮空输入。注意红色标记,这两种模式很重要,注意其区别。
2、在USART的配置中,通过USART_InitTypeDdf结构体对USART进行初始化操作。如用中断方式:在USART配置中要打开串口中断。
3、在NVIC的配置中主要是USARTx_IRQChannel的配置。
下面是一段配置代码:
void USART1_Configuration(void)
{
USART_InitTypeDef USART_InitStructure;
USART_ClockInitTypeDef USART_ClockInitStruct;
GPIO_InitTypeDef GPIO_InitStructure;
RCC_APB2PeriphClockCmd(RCC_APB2Periph_USART1, ENABLE); //开启USART1时钟
//配置PA9作为USART1 Tx
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_9;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;
GPIO_Init(GPIOA , &GPIO_InitStructure);
//配置PA10作为USART1 Rx
GPIO_InitStructure.GPIO_Pin = GPIO_Pin_10;
GPIO_InitStructure.GPIO_Speed = GPIO_Speed_50MHz;
GPIO_InitStructure.GPIO_Mode = GPIO_Mode_IN_FLOATING;
GPIO_Init(GPIOA , &GPIO_InitStructure);
//配置USART1
//中断被屏蔽了
USART_InitStructure.USART_BaudRate = 9600; //波特率可以通过地面站配置
USART_InitStructure.USART_WordLength = USART_WordLength_8b; //8位数据
USART_InitStructure.USART_StopBits = USART_StopBits_1; //在帧结尾传输1个停止位
USART_InitStructure.USART_Parity = USART_Parity_No; //禁用奇偶校验
USART_InitStructure.USART_HardwareFlowControl = USART_HardwareFlowControl_None; //硬件流控制失能
USART_InitStructure.USART_Mode = USART_Mode_Tx | USART_Mode_Rx; //发送、接收使能
//配置USART1时钟
USART_ClockInitStruct.USART_Clock = USART_Clock_Disable; //时钟低电平活动
USART_ClockInitStruct.USART_CPOL = USART_CPOL_Low; //SLCK引脚上时钟输出的极性->低电平
USART_ClockInitStruct.USART_CPHA = USART_CPHA_2Edge; //时钟第二个边沿进行数据捕获
USART_ClockInitStruct.USART_LastBit = USART_LastBit_Disable; //最后一位数据的时钟脉冲不从SCLK输出
USART_Init(USART1, &USART_InitStructure);
USART_ClockInit(USART1, &USART_ClockInitStruct);
/* Enable USART1 DMA TX request */
USART_DMACmd(USART1, USART_DMAReq_Tx, ENABLE);
//使能USART1接收中断
USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);
//使能USART1
USART_Cmd(USART1, ENABLE);
}
void NVIC_Configuration(void)//配置中断
{
NVIC_InitTypeDef NVIC_InitStructure;
#ifdef VECT_TAB_RAM
//将向量表起始地址设置为0x00000000
NVIC_SetVectorTable(NVIC_VectTab_RAM, 0x0);
#else //VECT_TAB_FLASH
NVIC_SetVectorTable(NVIC_VectTab_FLASH, 0x0);
#endif
//配置用1位表示优先级
NVIC_PriorityGroupConfig(NVIC_PriorityGroup_1); //选择第1组优先级 解释如下第
//0 组:所有 4bit 用于指定响应优先级;
//第 1 组:最高 1 位用于指定抢占式优先级,后面 3 位用于指定响应优先级;
//第 2 组:最高 2 位用于指定抢占式优先级,后面 2 位用于指定响应优先级;
//第 3 组:最高 3 位用于指定抢占式优先级,后面 1 位用于指定响应优先级;
//第 4 组:所有 4 位用于指定抢占式优先级。
//允许USART1中断
NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;//选择串口1中断
NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 1;
NVIC_InitStructure.NVIC_IRQChannelSubPriority = 2;
NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;
NVIC_Init(&NVIC_InitStructure);
}
/**************************************************************************************
函数名:USART1_SendData
描述 :USART1发送函数
输入 :无
输出 :无
返回 :无
**************************************************************************************/
void USART1_SendData(uint16_t Data)
{
USART1->DR = (Data & (uint16_t)0x01FF);
while(((USART1->SR)&0x0080)==RESET);
}
/****************************************************************************
* 名称:USART1_Printf()
* 功能:向串口发送一字符串 用法同Printf()函数
* 入口参数:format 要发送的字符串的指针 ... 为参数
* 出口参数:发送的字符串的字符个数
****************************************************************************/
int USART1_Printf(const char *format, ...)
{
va_list v_list;
char *ptr;
int i= 0;
va_start(v_list, format); // Initialize variable arguments.
vsprintf(tbuf1, format, v_list );
va_end(v_list);
ptr= tbuf1;
while( (*ptr) && i<MAX_TBUF1) {
USART1_SendData(*ptr);
ptr++; i++;
}//while
return i;
}
void USART1_IRQHandler(void) //中断接收函数
{
if((USART1->SR)&0x0020) //是否接收中断 (接收寄存器非空)
{
//写入执行动作
}
USART1->SR = 0xFFDF;
}
注意1:
所谓抢占式优先级和响应优先级,他们之间的关系是:具有高抢占式优先级的中断可以在具有低抢占式优先级
的中断处理过程中被响应,即中断嵌套。
当两个中断源的抢占式优先级相同时,这两个中断将没有嵌套关系,当一个中断到来后,如果正在处理另一个
中断,这个后到来的中断就要等到前一个中断处理完之后才能被处理。如果这两个中断同时到达,则中断控制器根
据他们的响应优先级高低来决定先处理哪一个;如果他们的抢占式优先级和响应优先级都相等,则根据他们在中断
表中的排位顺序决定先处理哪一个。每一个中断源都必须定义 2 个优先级。
有几点需要注意的是:
1)如果指定的抢占式优先级别或响应优先级别超出了选定的优先级分组所限定的范围,将可能得到意想不到的结
果;
2)抢占式优先级别相同的中断源之间没有嵌套关系;
3)如果某个中断源被指定为某个抢占式优先级别,又没有其它中断源处于同一个抢占式优先级别,则可以为这个
中断源指定任意有效的响应优先级别。
注意2:
注意在对数据进行发送和接收的时候,要检查 USART 的状态,只有等到数据发送或接收完毕之后才能进行下
一帧数据的发送或接收。采用 USART_GetFlagStatus()函数。
同时还要注意的是,在发送数据的最开始,需要清除一下 USART 的标志位,否则,第 1 位数据会丢失。因为
在硬件复位之后,USART 的状态位 TC 是置位的。当包含有数据的一帧发送完成之后,由硬件将该位置位。只要当
USART 的状态位 TC 是置位的时候,就可以进行数据的发送。然后 TC 位的置零则是通过软件序列来清除的,具体的
步骤是“先读 USART_SR,然后写入 USART_DR”,只有这样才能够清除标志位 TC,但是在发送第一帧数据的
时候,并没有进行读 USART_SR 的操作,而是直接进行写操作,因此 TC 标志位并没有清空,那么,当发送第一帧
数据,然后用 USART_GetFlagStatus()检测状态时返回的是已经发送完毕(因为 TC 位是置 1 的),所以程序会马上
发送下一帧数据,那么这样,第一帧数据就被第二帧数据给覆盖了,所以看不到第一帧数据的发送。