最近使用c8051做开发,串口程序移入工程时,整个程序竟然不跑了,加断点,调试,发现在串口查询发送出了问题,程序在查询发送完毕的时候,竟然死在这,就是while(TI0==0)这地方,用其它型号单片机没有这种情况,c8051F120单片机强大无比,但也复杂,用起来不顺手,下面就搜集了有关串口中断发送的资料,改为中断发送解决程序死的问题。
有关串口发送的程序例子:
- 假设要发送一组数据 Send[10]
- 一般采用查询发送(循环发送)方式:
- unsigned char Send[10]; //发送量
- unsigned char i; //循环量
- for(i = 0; i < 10; i++)
- {
- SBUF = Send[i]; //发送
- while(TI == 0); //等待发送完成
- TI = 0; //清标志
- }
- 采用中断发送方式:
- unsigned char Send[10]; //发送量
- unsigned char num; //发送数据量
- unsigned char *p; //发送用指针
- //发送时:
- num = 10; //定义发送数据量
- p = &Send ; //取首地址
- SBUF = *p; //发送第一个数据,启动发送中断
- //中断代码:
- void ComInt() interrupt 4
- {
- if(RI) RI = 0; //接收中断略;
- if(TI) //发送中断处理
- {
- TI = 0; //清标志
- num--; //计数减1
- p++; //指针加1
- if(num > 0) SBUF = *p; //数据继续发送至全部发完
- }
- }
对这个程序例子,网上给出这样的评价:
中断发送优点:省去循环等待时间,以上面例子为例,9600bps时查询发送约占用单片机10ms多,而中断发送只占单片机几十微秒(单片机速度 越快,占用时间越少)。
- #include <c8051f120.h> // SFR declarations
- #include <stdio.h>
- //-----------------------------------------------------------------------------
- // 16-bit SFR Definitions for 'F12x
- //-----------------------------------------------------------------------------
- sfr16 RCAP2 = 0xca; // Timer2 capture/reload
- sfr16 TMR2 = 0xcc; // Timer2
- //-----------------------------------------------------------------------------
- // Global Constants
- //-----------------------------------------------------------------------------
- #define BAUDRATE 115200 // Baud rate of UART in bps
- // SYSTEMCLOCK = System clock frequency in Hz
- #define SYSTEMCLOCK (22118400L * 9 / 4)
- //-----------------------------------------------------------------------------
- // Function Prototypes
- //-----------------------------------------------------------------------------
- void OSCILLATOR_Init (void);
- void PORT_Init (void);
- void UART0_Init (void);
- //-----------------------------------------------------------------------------
- // Global Variables
- //-----------------------------------------------------------------------------
- #define UART_BUFFERSIZE 64
- unsigned char UART_Buffer[UART_BUFFERSIZE];
- unsigned char UART_Buffer_Size = 0;
- unsigned char UART_Input_First = 0;
- unsigned char UART_Output_First = 0;
- unsigned char TX_Ready =1;
- static char Byte;
- //-----------------------------------------------------------------------------
- // main() Routine
- //-----------------------------------------------------------------------------
- void main (void)
- {
- SFRPAGE = CONFIG_PAGE;
- WDTCN = 0xDE; // Disable watchdog timer
- WDTCN = 0xAD;
- OSCILLATOR_Init (); // Initialize oscillator
- PORT_Init (); // Initialize crossbar and GPIO
- UART0_Init (); // Initialize UART0
- EA = 1;
- SFRPAGE = UART0_PAGE;
- while (1)
- {
- // If the complete word has been entered via the terminal followed
- // by carriage return
- if((TX_Ready == 1) && (UART_Buffer_Size != 0) && (Byte == 13))
- {
- TX_Ready = 0; // Set the flag to zero
- TI0 = 1; // Sed
- }
- }
- //-----------------------------------------------------------------------------
- // Initialization Subroutines
- //-----------------------------------------------------------------------------
- //-----------------------------------------------------------------------------
- // OSCILLATOR_Init
- //-----------------------------------------------------------------------------
- //
- // Return Value : None
- // Parameters : None
- //
- // This function initializes the system clock to use the PLL as its clock
- // source, where the PLL multiplies the external 22.1184MHz crystal by 9/4.
- //
- //-----------------------------------------------------------------------------
- void OSCILLATOR_Init (void)
- {
- int i; // Software timer
- char SFRPAGESFRPAGE_SAVE = SFRPAGE; // Save Current SFR page
- SFRPAGE = CONFIG_PAGE; // Set SFR page
- OSCICN = 0x80; // Set internal oscillator to run
- // at its slowest frequency
- CLKSEL = 0x00; // Select the internal osc. as
- // the SYSTEMCLOCK source
- // Initialize external crystal oscillator to use 22.1184 MHz crystal
- OSCXCN = 0x67; // Enable external crystal osc.
- for (i=0; i < 256; i++); // Wait at least 1ms
- while (!(OSCXCN & 0x80)); // Wait for crystal osc to settle
- SFRPAGE = LEGACY_PAGE;
- FLSCL |= 0x30; // Initially set FLASH read timing for
- // 100MHz SYSTEMCLOCK (most conservative
- // setting)
- if (SYSTEMCLOCK <= 25000000) {
- // Set FLASH read timing for <=25MHz
- FLSCL &= ~0x30;
- } else if (SYSTEMCLOCK <= 50000000) {
- // Set FLASH read timing for <=50MHz
- FLSCL &= ~0x20;
- } else if (SYSTEMCLOCK <= 75000000) {
- // Set FLASH read timing for <=75MHz
- FLSCL &= ~0x10;
- } else { // set FLASH read timing for <=100MHz
- FLSCL &= ~0x00;
- }
- // Start PLL for 50MHz operation
- SFRPAGE = PLL0_PAGE;
- PLL0CN = 0x04; // Select EXTOSC as clk source
- PLL0CN |= 0x01; // Enable PLL power
- PLL0DIV = 0x04; // Divide by 4
- PLL0FLT &= ~0x0f;
- PLL0FLT |= 0x0f; // Set Loop Filt for (22/4)MHz input clock
- PLL0FLT &= ~0x30; // Set ICO for 30-60MHz
- PLL0FLT |= 0x10;
- PLL0MUL = 0x09; // Multiply by 9
- // wait at least 5us
- for (i = 0; i < 256; i++) ;
- PLL0CN |= 0x02; // Enable PLL
- while (PLL0CN & 0x10 == 0x00); // Wait for PLL to lock
- SFRPAGE = CONFIG_PAGE;
- CLKSEL = 0x02; // Select PLL as SYSTEMCLOCK source
- SFRPAGE = SFRPAGE_SAVE; // Restore SFRPAGE
- }
- //-----------------------------------------------------------------------------
- // PORT_Init
- //-----------------------------------------------------------------------------
- //
- // Return Value : None
- // Parameters : None
- //
- // This function configures the crossbar and GPIO ports.
- //
- // P0.0 digital push-pull UART TX
- // P0.1 digital open-drain UART RX
- //-----------------------------------------------------------------------------
- void PORT_Init (void)
- {
- char SFRPAGESFRPAGE_SAVE = SFRPAGE; // Save Current SFR page
- SFRPAGE = CONFIG_PAGE; // Set SFR page
- XBR0 = 0x04; // Enable UART0
- XBR1 = 0x00;
- XBR2 = 0x40; // Enable crossbar and weak pull-up
- P0MDOUT |= 0x01; // Set TX pin to push-pull
- P1MDOUT |= 0x40; // Set P1.6(LED) to push-pull
- SFRPAGE = SFRPAGE_SAVE; // Restore SFR page
- }
- //-----------------------------------------------------------------------------
- // UART0_Init Variable baud rate, Timer 2, 8-N-1
- //-----------------------------------------------------------------------------
- //
- // Return Value : None
- // Parameters : None
- //
- // Configure UART0 for operation at <baudrate> 8-N-1 using Timer2 as
- // baud rate source.
- //
- //-----------------------------------------------------------------------------
- void UART0_Init (void)
- {
- char SFRPAGE_SAVE;
- SFRPAGESFRPAGE_SAVE = SFRPAGE; // Preserve SFRPAGE
- SFRPAGE = TMR2_PAGE;
- TMR2CN = 0x00; // Timer in 16-bit auto-reload up timer
- // mode
- TMR2CF = 0x08; // SYSCLK is time base; no output;
- // up count only
- RCAP2 = - ((long) SYSTEMCLOCK/BAUDRATE/16);
- TMR2 = RCAP2;
- TR2= 1; // Start Timer2
- SFRPAGE = UART0_PAGE;
- SCON0 = 0x50; // 8-bit variable baud rate;
- // 9th bit ignored; RX enabled
- // clear all flags
- SSTA0 = 0x15; // Clear all flags; enable baud rate
- // doubler (not relevant for these
- // timers);
- // Use Timer2 as RX and TX baud rate
- // source;
- ES0 = 1;
- IP |= 0x10;
- SFRPAGE = SFRPAGE_SAVE; // Restore SFRPAGE
- }
- //-----------------------------------------------------------------------------
- // Interrupt Service Routines
- //-----------------------------------------------------------------------------
- //-----------------------------------------------------------------------------
- // UART0_Interrupt
- //-----------------------------------------------------------------------------
- //
- // This routine is invoked whenever a character is entered or displayed on the
- // Hyperterminal.
- //
- //-----------------------------------------------------------------------------
- void UART0_Interrupt (void) interrupt 4
- {
- SFRPAGE = UART0_PAGE;
- if (RI0 == 1)
- {
- if( UART_Buffer_Size == 0) { // If new word is entered
- UART_Input_First = 0; }
- RI0 = 0; // Clear interrupt flag
- Byte = SBUF0; // Read a character from UART
- if (UART_Buffer_Size < UART_BUFFERSIZE)
- {
- UART_Buffer[UART_Input_First] = Byte; // Store in array
- UART_Buffer_Size++; // Update array's size
- UART_Input_First++; // Update counter
- }
- }
- if (TI0 == 1) // Check if transmit flag is set
- {
- TI0 = 0; // Clear interrupt flag
- if (UART_Buffer_Size != 1) // If buffer not empty
- {
- // If a new word is being output
- if ( UART_Buffer_Size == UART_Input_First ) {
- UART_Output_First = 0; }
- // Store a character in the variable byte
- Byte = UART_Buffer[UART_Output_First];
- if ((Byte >= 0x61) && (Byte <= 0x7A)) { // If upper case letter
- Byte -= 32; }
- SBUF0 = Byte; // Transmit to Hyperterminal
- UART_Output_First++; // Update counter
- UART_Buffer_Size--; // Decrease array size
- }
- else
- {
- UART_Buffer_Size = 0; // Set the array size to 0
- TX_Ready = 1; // Indicate transmission complete
- }
- }
- }
- //-----------------------------------------------------------------------------
- // End Of File
- //-----------------------------------------------------------------------------
看看人家例程,说得很明白,中断式接收和发送,好好读读人家程序,不错的。