為了解決 USART 重複觸發問題查詢很多網上資料 一直未有可靠的斬獲
直到找到 "amoBBS 阿莫电子论坛" 有下面的討論 才引發我去驗證的決心, 分享給諸君參考!
結論如下:
1: Flag 說明:
USART_IT_TC: Transmission complete interrupt .
USART_IT_TXE: Tansmit Data Register empty interrupt
USART_IT_RXNE: Receive Data register not empty interrupt.
2: 根據說明驗證
於 USART1_IRQHandler(void) 內宣告 變數 u16 srreg 作為回讀確認 USART->SR Flag 讀值buffer
3 確認事項
** drreg = USARTDR 讀取 USARTDR , TXE Flag 狀態不變!
與網路上有的說明 回讀USARTDR TXE清為 0 不符
** 將 USARTSR = 0x0000 強制寫入 0 TXE Flag 無法歸零
** darareg = USARTDR R/W data buffer TXE Flag 會歸零
** 寫入 USARTSR = 0x0000 then TC and RXEN Flag 可以 歸零
4: 由此 可以確認
USART_ITConfig(USART1, USART_IT_TXE, ENABLE); 會引發產生接收中斷
USART_ITConfig(USART1, USART_IT_TC, ENABLE); 使用傳送結束中斷較理想!
在void
USART_Config(void)串口初始化函数中设置了USART_ITConfig(USART1, USART_IT_TXE,
ENABLE);,
对“发送数据寄存器空”中断进行了使能。
其中TXE中断的描述是如下(STM32F10x微控制器参考手册(2008年12月第7版).pdf,P494)
______________________________________________________________________________
| TXE:发送数据寄存器空
|
当TDR寄存器中的数据被硬件转移到移位寄存器的时候,该位被硬件置位。
| 如果USART_CR1 寄存器中的TXEIE为1,则产生中断。对USART_DR的写操作,将该位清零。
| 如果USART_CR1 寄存器中的TXEIE为1,则产生中断。对USART_DR的写操作,将该位清零。
|
0:数据还没有被转移到移位寄存器;
|
1:数据已经被转移到移位寄存器。
| 注意:单缓冲器传输中使用该位。
|_____________________________________________________________________________
其中提到该位的清零只能由对对USART_DR的写操作来完成。而我在原来的程序里面使用了
USART_ClearITPendingBit(USART1
,USART_IT_TXE);
这句话,本意是想在ISR中清除
发送数据寄存器空 中断,实际上只是一厢情愿,并不能达到清中断标志的目的。
跟踪USART_ClearITPendingBit();函数,发现在函数说明中,这个函数并不能对USART_IT_TXE进行操作,原来的写法有误。
/*******************************************************************************
* Function
Name : USART_ClearITPendingBit
* Description
: Clears the USARTx interrupt pending bits.
* Input
: - USARTx: Select the USART or the UART
peripheral.
*
This
parameter can be one of the following values:
*
-
USART1, USART2, USART3, UART4 or UART5.
*
- USART_IT: specifies
the interrupt pending bit to clear.
*
This
parameter can be one of the following values:
*
- USART_IT_CTS: CTS change interrupt (not
available for
*
UART4
and UART5)
*
- USART_IT_LBD: LIN Break detection interrupt
*
- USART_IT_TC: Transmission complete
interrupt.
*
- USART_IT_RXNE: Receive Data register not empty interrupt.
*
- USART_IT_IDLE: Idle line detection interrupt.
*
- USART_IT_ORE: OverRun Error interrupt.
*
- USART_IT_NE: Noise Error interrupt.
*
- USART_IT_FE: Framing Error interrupt.
*
- USART_IT_PE: Parity Error interrupt.
* 可以看到,USART_IT_TXE并不能作为该函数的参数。
*
Note: -
For IDLE, ORE, NE, FE and PE pending bits user has to
*
read the USART DR register after calling this function.
*
- TXE pending bit can't be cleared by this function, it's
*
cleared only by a write to the USART DR register.
* Output
: None
* Return
: None
*******************************************************************************/
这就导致了上面提到的出现永无止尽的中断,因为
USART_DR 一直都是空的。
这样看来,我在 4 楼提到的
NVIC_Init()函数中
“NVIC->ISER[(NVIC_InitStruct->NVIC_IRQChannel
>> 0x05)] = (u32)0x01 << (NVIC_InitStruct->NVIC_IRQChannel &
(u8)0x1F);//这里触发了一次中断 ”
这样的描述是不对的,并不是触发软中断,只是这句话刚打开中断,CPU发现
USART_DR 是空的,于是就进入响应中断了。
解决办法:
1.
因为发送的数据量不是很大,只是打印几个字符信息而已,所以干脆就把发送空中断关了
2. 将原来发送一个字符的函数
void
putch(u8 c)
{
if(c=='\n')
{
USART_SendData(USART1, 0x0D);
while(!USART_GetITStatus(USART1,
USART_IT_TXE)); //将要改这里
USART_SendData(USART1, 0x0A);
while(!USART_GetITStatus(USART1,
USART_IT_TXE));
}
else
{
USART_SendData(USART1, (unsigned char)c);
while(!USART_GetITStatus(USART1,
USART_IT_TXE));
}
}//end
of void putch(u8 c)
改为
void
putch(u8 c)
{
if(c=='\n')
{
USART_SendData(USART1, 0x0D);
while (!(USART1->SR &
USART_FLAG_TXE)); //这里改动
USART_SendData(USART1, 0x0A);
while (!(USART1->SR & USART_FLAG_TXE));
}
else
{
USART_SendData(USART1, (unsigned char)c);
while (!(USART1->SR &
USART_FLAG_TXE));
}
沒有留言:
張貼留言