当前位置:首页 > 单片机 > 单片机
[导读]这次讲讲利用串口收发中断来进行串口通讯。STM32 上为每个串口分配了一个中断。也就是说无论是发送完成还是收到数据或是数据溢出都产生同一个中断。程序需在中断处理函数中读取状态寄存器(USART_SR)来判断当前的是什

这次讲讲利用串口收发中断来进行串口通讯。STM32 上为每个串口分配了一个中断。也就是说无论是发送完成还是收到数据或是数据溢出都产生同一个中断。程序需在中断处理函数中读取状态寄存器(USART_SR)来判断当前的是什么中断。下面的中断映像图给出了这些中断源是如何汇合成最终的中断信号的。图中也给出了如何控制每一个单独的中断源是否起作用。

另外,Cortex-M3内核中还有个NVIC,可以控制这里的中断信号是否触发中断处理函数的执行,还有这些外部中断的级别。关于NVIC可以参考《ARM CortexM3权威指南》,里面讲解的非常详细。

简单的说,为了开启中断,我们需要如下的代码:


NVIC_InitTypeDef NVIC_InitStructure;

NVIC_InitStructure.NVIC_IRQChannel = USART1_IRQn;

NVIC_InitStructure.NVIC_IRQChannelPreemptionPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelSubPriority = 0;

NVIC_InitStructure.NVIC_IRQChannelCmd = ENABLE;

NVIC_Init(&NVIC_InitStructure);

USART_ITConfig(USART1, USART_IT_RXNE, ENABLE);//开启接收中断

USART_ITConfig(USART1, USART_IT_TXE, ENABLE);// 开启发送中断

这里多说一句,串口的发送中断有两个,分别是:

l发送数据寄存器空中断(TXE)

l发送完成中断(TC)

一般来说我们会使用发送数据寄存器空中断,用这个中断发送的效率会高一些。

中断处理函数的框架如下,如果检测到错误就清除错误,收到数了就处理。发完当前数据了就发下一个。


voidUSART1_IRQHandler(void)

{

unsignedintdata;

if(USART1->SR & 0x0F)

{

// See if we have some kind of error, Clear interrupt

data = USART1->DR;

}

elseif(USART1->SR & USART_FLAG_RXNE)//Receive Data Reg Full Flag

{

data = USART1->DR;

// 对收到的数据进行处理,或者干些其他的事

}

elseif(USART1->SR & USART_FLAG_TXE)

{

{// 可以发送数据了,如果没有数据需要发送,就在这里关闭发送中断

USART1->DR = something;// Yes, Send character

}

}

}


下面给一个利用环形缓冲区的串口驱动程序。


#ifndef _COM_BUFFERED_H_

#define _COM_BUFFERED_H_

#define COM1 0

#define COM2 1

#define COM_RX_BUF_SIZE 64

#define COM_TX_BUF_SIZE 64

#define COM_NO_ERR 0

#define COM_BAD_CH 1

#define COM_RX_EMPTY 2

#define COM_TX_FULL 3

#define COM_TX_EMPTY 4

unsignedcharCOMGetCharB (unsignedcharch, unsignedchar*err);

unsignedcharCOMPutCharB (unsignedcharport, unsignedcharc);

voidCOMBufferInit (void);

unsignedcharCOMBufferIsEmpty (unsignedcharport);

unsignedcharCOMBufferIsFull (unsignedcharport);

#endif



#include "stm32f10x_usart.h"

#include "com_buffered.h"

#define OS_ENTER_CRITICAL() __set_PRIMASK(1)

#define OS_EXIT_CRITICAL() __set_PRIMASK(0)

staticvoidCOMEnableTxInt(unsignedcharport)

{

staticUSART_TypeDef* map[2] = {USART1, USART2};

USART_ITConfig(map[port], USART_IT_TXE, ENABLE);

}

typedefstruct{

shortRingBufRxCtr;

unsignedchar*RingBufRxInPtr;

unsignedchar*RingBufRxOutPtr;

unsignedcharRingBufRx[COM_RX_BUF_SIZE];

shortRingBufTxCtr;

unsignedchar*RingBufTxInPtr;

unsignedchar*RingBufTxOutPtr;

unsignedcharRingBufTx[COM_TX_BUF_SIZE];

} COM_RING_BUF;

COM_RING_BUF COM1Buf;

COM_RING_BUF COM2Buf;

unsignedcharCOMGetCharB (unsignedcharport, unsignedchar*err)

{

// unsigned char cpu_sr;

unsignedcharc;

COM_RING_BUF *pbuf;

switch(port)

{

caseCOM1:

pbuf = &COM1Buf;

break;

caseCOM2:

pbuf = &COM2Buf;

break;

default:

*err = COM_BAD_CH;

return(0);

}

OS_ENTER_CRITICAL();

if(pbuf->RingBufRxCtr > 0)

{

pbuf->RingBufRxCtr--;

c = *pbuf->RingBufRxOutPtr++;

if(pbuf->RingBufRxOutPtr == &pbuf->RingBufRx[COM_RX_BUF_SIZE])

{

pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0];

}

OS_EXIT_CRITICAL();

*err = COM_NO_ERR;

return(c);

}else{

OS_EXIT_CRITICAL();

*err = COM_RX_EMPTY;

c = 0;

return(c);

}

}

unsignedcharCOMPutCharB (unsignedcharport, unsignedcharc)

{

// unsigned char cpu_sr;

COM_RING_BUF *pbuf;

switch(port)

{

caseCOM1:

pbuf = &COM1Buf;

break;

caseCOM2:

pbuf = &COM2Buf;

break;

default:

return(COM_BAD_CH);

}

OS_ENTER_CRITICAL();

if(pbuf->RingBufTxCtr < COM_TX_BUF_SIZE) {

pbuf->RingBufTxCtr++;

*pbuf->RingBufTxInPtr++ = c;

if(pbuf->RingBufTxInPtr == &pbuf->RingBufTx[COM_TX_BUF_SIZE]) {

pbuf->RingBufTxInPtr = &pbuf->RingBufTx[0];

}

if(pbuf->RingBufTxCtr == 1) {

COMEnableTxInt(port);

OS_EXIT_CRITICAL();

}else{

OS_EXIT_CRITICAL();

}

return(COM_NO_ERR);

}else{

OS_EXIT_CRITICAL();

return(COM_TX_FULL);

}

}

voidCOMBufferInit (void)

{

COM_RING_BUF *pbuf;

pbuf = &COM1Buf;

pbuf->RingBufRxCtr = 0;

pbuf->RingBufRxInPtr = &pbuf->RingBufRx[0];

pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0];

pbuf->RingBufTxCtr = 0;

pbuf->RingBufTxInPtr = &pbuf->RingBufTx[0];

pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0];

pbuf = &COM2Buf;

pbuf->RingBufRxCtr = 0;

pbuf->RingBufRxInPtr = &pbuf->RingBufRx[0];

pbuf->RingBufRxOutPtr = &pbuf->RingBufRx[0];

pbuf->RingBufTxCtr = 0;

pbuf->RingBufTxInPtr = &pbuf->RingBufTx[0];

pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0];

}

unsignedcharCOMBufferIsEmpty (unsignedcharport)

{

// unsigned char cpu_sr;

unsignedcharempty;

COM_RING_BUF *pbuf;

switch(port)

{

caseCOM1:

pbuf = &COM1Buf;

break;

caseCOM2:

pbuf = &COM2Buf;

break;

default:

return(1);

}

OS_ENTER_CRITICAL();

if(pbuf->RingBufRxCtr > 0)

{

empty = 0;

}

else

{

empty = 1;

}

OS_EXIT_CRITICAL();

return(empty);

}

unsignedcharCOMBufferIsFull (unsignedcharport)

{

// unsigned char cpu_sr;

charfull;

COM_RING_BUF *pbuf;

switch(port)

{

caseCOM1:

pbuf = &COM1Buf;

break;

caseCOM2:

pbuf = &COM2Buf;

break;

default:

return(1);

}

OS_ENTER_CRITICAL();

if(pbuf->RingBufTxCtr < COM_TX_BUF_SIZE) {

full = 0;

}else{

full = 1;

}

OS_EXIT_CRITICAL();

return(full);

}

// This function is called by the Rx ISR to insert a character into the receive ring buffer.

staticvoidCOMPutRxChar (unsignedcharport, unsignedcharc)

{

COM_RING_BUF *pbuf;

switch(port)

{

caseCOM1:

pbuf = &COM1Buf;

break;

caseCOM2:

pbuf = &COM2Buf;

break;

default:

return;

}

if(pbuf->RingBufRxCtr < COM_RX_BUF_SIZE) {

pbuf->RingBufRxCtr++;

*pbuf->RingBufRxInPtr++ = c;

if(pbuf->RingBufRxInPtr == &pbuf->RingBufRx[COM_RX_BUF_SIZE]) {

pbuf->RingBufRxInPtr = &pbuf->RingBufRx[0];

}

}

}

// This function is called by the Tx ISR to extract the next character from the Tx buffer.

// The function returns FALSE if the buffer is empty after the character is extracted from

// the buffer. This is done to signal the Tx ISR to disable interrupts because this is the

// last character to send.

staticunsignedcharCOMGetTxChar (unsignedcharport, unsignedchar*err)

{

unsignedcharc;

COM_RING_BUF *pbuf;

switch(port)

{

caseCOM1:

pbuf = &COM1Buf;

break;

caseCOM2:

pbuf = &COM2Buf;

break;

default:

*err = COM_BAD_CH;

return(0);

}

if(pbuf->RingBufTxCtr > 0) {

pbuf->RingBufTxCtr--;

c = *pbuf->RingBufTxOutPtr++;

if(pbuf->RingBufTxOutPtr == &pbuf->RingBufTx[COM_TX_BUF_SIZE])

{

pbuf->RingBufTxOutPtr = &pbuf->RingBufTx[0];

}

*err = COM_NO_ERR;

return(c);

}else{

*err = COM_TX_EMPTY;

return(0);

}

}

voidUSART1_IRQHandler(void)

{

unsignedintdata;

unsignedcharerr;

if(USART1->SR & 0x0F)

{

// See if we have some kind of error

// Clear interrupt (do nothing about it!)

data = USART1->DR;

}

elseif(USART1->SR & USART_FLAG_RXNE)//Receive Data Reg Full Flag

{

data = USART1->DR;

COMPutRxChar(COM1, data);// Insert received character into buffer

}

elseif(USART1->SR & USART_FLAG_TXE)

{

data = COMGetTxChar(COM1, &err);// Get next character to send.

if(err == COM_TX_EMPTY)

{// Do we have anymore characters to send ?

// No, Disable Tx interrupts

//USART_ITConfig(USART1, USART_IT_TXE| USART_IT_TC, ENABLE);

USART1->CR1 &= ~USART_FLAG_TXE | USART_FLAG_TC;

}

else

{

USART1->DR = data;// Yes, Send character

}

}

}

voidUSART2_IRQHandler(void)

{

unsignedintdata;

unsignedcharerr;

if(USART2->SR & 0x0F)

{

// See if we have some kind of error

// Clear interrupt (do nothing about it!)

data = USART2->DR;

}

elseif(USART2->SR & USART_FLAG_RXNE)//Receive Data Reg Full Flag

{

data = USART2->DR;

COMPutRxChar(COM2, data);// Insert received character into buffer

}

elseif(USART2->SR & USART_FLAG_TXE)

{

data = COMGetTxChar(COM2, &err);// Get next character to send.

if(err == COM_TX_EMPTY)

{// Do we have anymore characters to send ?

// No, Disable Tx interrupts

//USART_ITConfig(USART2, USART_IT_TXE| USART_IT_TC, ENABLE);

USART2->CR1 &= ~USART_FLAG_TXE | USART_FLAG_TC;

}

else

{

USART2->DR = data;// Yes, Send character

}

}

}


下面给个例子主程序,来演示如何使用上面的串口驱动代码。


#include "misc.h"

#include "stm32f10x.h"

#include "com_buffered.h"

voidUART_PutStrB (unsignedcharport, uint8_t *str)

{

while(0 != *str)

{

COMPutCharB(port, *str);

str++;

}

}

voidUSART1_Init(void)

{

GPIO_InitTypeDef GPIO_InitStructure;

USART_InitTypeDef USART_InitStructure;

NVIC_InitTypeDef NVIC_InitStructure;

RCC_APB2PeriphClockCmd(RCC_APB2Periph_GPIOA | RCC_APB2Periph_USART1, ENABLE);

GPIO_InitStructure.GPIO_Mode = GPIO_Mode_AF_PP;

GP

本站声明: 本文章由作者或相关机构授权发布,目的在于传递更多信息,并不代表本站赞同其观点,本站亦不保证或承诺内容真实性等。需要转载请联系该专栏作者,如若文章内容侵犯您的权益,请及时联系本站删除。
换一批
延伸阅读

9月2日消息,不造车的华为或将催生出更大的独角兽公司,随着阿维塔和赛力斯的入局,华为引望愈发显得引人瞩目。

关键字: 阿维塔 塞力斯 华为

加利福尼亚州圣克拉拉县2024年8月30日 /美通社/ -- 数字化转型技术解决方案公司Trianz今天宣布,该公司与Amazon Web Services (AWS)签订了...

关键字: AWS AN BSP 数字化

伦敦2024年8月29日 /美通社/ -- 英国汽车技术公司SODA.Auto推出其旗舰产品SODA V,这是全球首款涵盖汽车工程师从创意到认证的所有需求的工具,可用于创建软件定义汽车。 SODA V工具的开发耗时1.5...

关键字: 汽车 人工智能 智能驱动 BSP

北京2024年8月28日 /美通社/ -- 越来越多用户希望企业业务能7×24不间断运行,同时企业却面临越来越多业务中断的风险,如企业系统复杂性的增加,频繁的功能更新和发布等。如何确保业务连续性,提升韧性,成...

关键字: 亚马逊 解密 控制平面 BSP

8月30日消息,据媒体报道,腾讯和网易近期正在缩减他们对日本游戏市场的投资。

关键字: 腾讯 编码器 CPU

8月28日消息,今天上午,2024中国国际大数据产业博览会开幕式在贵阳举行,华为董事、质量流程IT总裁陶景文发表了演讲。

关键字: 华为 12nm EDA 半导体

8月28日消息,在2024中国国际大数据产业博览会上,华为常务董事、华为云CEO张平安发表演讲称,数字世界的话语权最终是由生态的繁荣决定的。

关键字: 华为 12nm 手机 卫星通信

要点: 有效应对环境变化,经营业绩稳中有升 落实提质增效举措,毛利润率延续升势 战略布局成效显著,战新业务引领增长 以科技创新为引领,提升企业核心竞争力 坚持高质量发展策略,塑强核心竞争优势...

关键字: 通信 BSP 电信运营商 数字经济

北京2024年8月27日 /美通社/ -- 8月21日,由中央广播电视总台与中国电影电视技术学会联合牵头组建的NVI技术创新联盟在BIRTV2024超高清全产业链发展研讨会上宣布正式成立。 活动现场 NVI技术创新联...

关键字: VI 传输协议 音频 BSP

北京2024年8月27日 /美通社/ -- 在8月23日举办的2024年长三角生态绿色一体化发展示范区联合招商会上,软通动力信息技术(集团)股份有限公司(以下简称"软通动力")与长三角投资(上海)有限...

关键字: BSP 信息技术
关闭
关闭