我的平台是c8051F120微控制器。我想使用中断通过UART0发送(= tx)字节。到目前为止,我的设计如下:
#define UART0_TX_SIZE 16
char UART0_tx[UART0_TX_SIZE];
short UART0_tx_uart = 0;
short UART0_tx_main = 0;
short UART0_tx_available = 0;
void UART0_putChar(char value) {
char SAVE_SFRPAGE;
bit EA_SAVE = EA;
// potentially blocking code
while (UART0_tx_available == UART0_TX_SIZE)
;
// disable interrupts
EA = 0;
EA = 0;
if (UART0_tx_available) {
UART0_tx[UART0_tx_main] = value;
++UART0_tx_main;
if (UART0_tx_main == UART0_TX_SIZE)
UART0_tx_main = 0;
++UART0_tx_available;
} else {
SAVE_SFRPAGE = SFRPAGE;
SFRPAGE = UART0_PAGE;
SBUF0 = value;
SFRPAGE = SAVE_SFRPAGE;
}
// reenable if necessary
EA = EA_SAVE;
}
// (return void works for other interrupts)
void UART0_Interrupt() interrupt (4) {
if (RI0 == 1) {
RI0 = 0;
}
if (TI0 == 1) { // cause of interrupt: previous tx is finished
TI0 = 0; // Q: Should this clear tx interrupt flag be further down?
if (SSTA0 & 0x20) { // Errors tx collision
SSTA0 &= 0xDF;
}
if (UART0_tx_available) { // If buffer not empty
--UART0_tx_available; // Decrease array size
SBUF0 = UART0_tx[UART0_tx_uart]; //Transmit
++UART0_tx_uart; //Update counter
if (UART0_tx_uart == UART0_TX_SIZE)
UART0_tx_uart = 0;
}
}
}
我很确定关于UART0寄存器的初始化和通过Timer2的时序(不是上面代码的一部分)是正确的,因为我能够使用阻塞功能:
char putchar_Blocking(char value) {
char SFRPAGE_SAVE = SFRPAGE;
SFRPAGE = UART0_PAGE;
while (!TI0) // while TI0 == 1 wait for transmit complete
;
TI0 = 0;
SBUF0 = value;
SFRPAGE = SFRPAGE_SAVE;
return value;
}
当我想切换到中断设计时,我当然也设置了
ES0 = 1;
是否有人发现我的设计中存在试图使用中断的缺陷?或者,是否有人为此提供示例代码?谢谢!对jszakmeister大声喊叫,他回答了我关于阅读TCNT注册的问题。
答案 0 :(得分:3)
我看到的最大缺陷是你不应该有任何变量(例如:UART0_tx_available)被主代码和中断代码修改。
通常我使用循环缓冲区和两个指针来实现中断驱动的UART。
这是AVR micro的简单C示例。我的8051代码都是汇编代码。
/* size of RX/TX buffers */
#define UART_RX_BUFFER_SIZE 16
#define UART_TX_BUFFER_SIZE 16
#define UART_RX_BUFFER_MASK ( UART_RX_BUFFER_SIZE - 1)
#define UART_TX_BUFFER_MASK ( UART_TX_BUFFER_SIZE - 1)
#if ( UART_RX_BUFFER_SIZE & UART_RX_BUFFER_MASK )
#error RX buffer size is not a power of 2
#endif
#if ( UART_TX_BUFFER_SIZE & UART_TX_BUFFER_MASK )
#error TX buffer size is not a power of 2
#endif
/*
* module global variables
*/
static volatile unsigned char UART_TxBuf[UART_TX_BUFFER_SIZE];
static volatile unsigned char UART_RxBuf[UART_RX_BUFFER_SIZE];
static volatile unsigned char UART_TxHead;
static volatile unsigned char UART_TxTail;
static volatile unsigned char UART_RxHead;
static volatile unsigned char UART_RxTail;
static volatile unsigned char UART_LastRxError;
SIGNAL(UART0_TRANSMIT_INTERRUPT)
/*************************************************************************
Function: UART Data Register Empty interrupt
Purpose: called when the UART is ready to transmit the next byte
**************************************************************************/
{
unsigned char tmptail;
if ( UART_TxHead != UART_TxTail) {
/* calculate and store new buffer index */
tmptail = (UART_TxTail + 1) & UART_TX_BUFFER_MASK;
/* get one byte from buffer and write it to UART */
UART0_DATA = UART_TxBuf[tmptail]; /* start transmission */
UART_TxTail = tmptail;
}else{
/* tx buffer empty, disable UDRE interrupt */
UART0_CONTROL &= ~_BV(UART0_UDRIE);
}
}
/*************************************************************************
Function: uart_putc()
Purpose: write byte to ringbuffer for transmitting via UART
Input: byte to be transmitted
Returns: none
**************************************************************************/
void uart_putc(unsigned char data)
{
unsigned char tmphead;
tmphead = (UART_TxHead + 1) & UART_TX_BUFFER_MASK;
while ( tmphead == UART_TxTail ){
;/* wait for free space in buffer */
}
UART_TxBuf[tmphead] = data;
UART_TxHead = tmphead;
/* enable UDRE interrupt */
UART0_CONTROL |= _BV(UART0_UDRIE);
}/* uart_putc */
特别感谢Peter Fleury http://jump.to/fleury这些例程来自图书馆。
答案 1 :(得分:0)
我的同事郭雄发现了错误:变量UART0_tx_available没有在正确的地方递增和递减。以下是经过修正和测试的版本:
#define UART0_TX_SIZE 16
char UART0_tx[UART0_TX_SIZE];
short UART0_tx_uart = 0;
short UART0_tx_main = 0;
short UART0_tx_available = 0;
void UART0_putChar(char value) {
char SAVE_SFRPAGE;
bit EA_SAVE = EA;
// potentially blocking code
while (UART0_tx_available == UART0_TX_SIZE)
;
// disable interrupts
EA = 0;
EA = 0;
if (UART0_tx_available) {
UART0_tx[UART0_tx_main] = value;
++UART0_tx_main;
if (UART0_tx_main == UART0_TX_SIZE)
UART0_tx_main = 0;
} else {
SAVE_SFRPAGE = SFRPAGE;
SFRPAGE = UART0_PAGE;
SBUF0 = value;
SFRPAGE = SAVE_SFRPAGE;
}
++UART0_tx_available;
// reenable if necessary
EA = EA_SAVE;
}
// (return void works for other interrupts)
void UART0_Interrupt() interrupt (4) {
if (RI0 == 1) {
RI0 = 0;
}
if (TI0 == 1) { // cause of interrupt: previous tx is finished
TI0 = 0; // Q: Should this clear tx interrupt flag be further down?
if (SSTA0 & 0x20) { // Errors tx collision
SSTA0 &= 0xDF;
}
--UART0_tx_available; // Decrease array size
if (UART0_tx_available) { // If buffer not empty
SBUF0 = UART0_tx[UART0_tx_uart]; //Transmit
++UART0_tx_uart; //Update counter
if (UART0_tx_uart == UART0_TX_SIZE)
UART0_tx_uart = 0;
}
}
}