⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uart.c

📁 AVRGCC编写的很好用的串口通讯源程序
💻 C
字号:

#include <stdio.h>

#include <avr/io.h>
#include <avr/interrupt.h>
#include <avr/signal.h>
#include <avrx/avrx.h>

#include "hardware.h"
#include "uart.h"

// USART Receiver buffer
uint8_t rx_buffer[RX_BUFFER_SIZE];
uint8_t volatile rx_wr, rx_count;
uint8_t rx_rd;
Mutex rx_rdy;
// This flag is set on USART Receiver buffer overflow
uint8_t rx_buffer_overflow;

// USART Transmitter buffer
uint8_t tx_buffer[TX_BUFFER_SIZE];
uint8_t tx_wr;
uint8_t volatile tx_rd, tx_count;
Mutex tx_rdy;

// USART Receiver interrupt service routine
AVRX_SIGINT(SIG_UART_RECV)
{
	uint8_t status, data;
	
	IntProlog();
	status = UCSRA;
	data = UDR;
	if ((status & (_BV(FE) | _BV(PE) | _BV(DOR))) == 0)
	{
		rx_buffer[rx_wr] = data;
		
		if (++rx_wr == RX_BUFFER_SIZE)
		{
			rx_wr = 0;
		}
		if (++rx_count == RX_BUFFER_SIZE)
		{
			rx_count = 0;
			rx_buffer_overflow = 1;
		}
		else
		{
			AvrXIntSetSemaphore(&rx_rdy);
		}
	}
	Epilog();
}

// USART Transmitter interrupt service routine
AVRX_SIGINT(SIG_UART_TRANS)
{
	IntProlog();
	if (tx_count)
	{
		UDR = tx_buffer[tx_rd];
		if (++tx_rd == TX_BUFFER_SIZE) tx_rd = 0;
		--tx_count;
		AvrXIntSetSemaphore(&tx_rdy);
	}
	Epilog();
}

int
UartGetc(void)
{
	uint8_t data;
	
	if (0 == rx_count)
	{
		AvrXWaitSemaphore(&rx_rdy);
	}
	data = rx_buffer[rx_rd];
	if (++rx_rd == RX_BUFFER_SIZE)
	{
		rx_rd = 0;
	}
	BeginCritical();
	if (0 == --rx_count)
	{
		AvrXResetSemaphore(&rx_rdy);
	}
	EndCritical();
	
	return data;
}

int
UartPutc(char c)
{
	if (tx_count == TX_BUFFER_SIZE)
	{
		AvrXWaitSemaphore(&tx_rdy);
	}
	BeginCritical();
	if (tx_count || bit_is_clear(UCSRA, UDRE))
	{
		tx_buffer[tx_wr] = c;
		if (++tx_wr == TX_BUFFER_SIZE)
		{
			tx_wr = 0;
		}
		if (++tx_count == TX_BUFFER_SIZE)
		{
			AvrXResetSemaphore(&tx_rdy);
		}
	}
	else
	{
		UDR = c;
	}
	EndCritical();
	
	return 0;
}

void
UartInit(void)
{
	uint32_t uart_param;
	
	AvrXResetSemaphore(&rx_rdy);
	AvrXResetSemaphore(&tx_rdy);
	
	uart_param = UART_DEFAULT_DATABITS;
	UartIOCtl(UART_SETDATABITS, &uart_param);
	uart_param = UART_DEFAULT_PARITY;
	UartIOCtl(UART_SETPARITY, &uart_param);
	uart_param = UART__DEFAULT_STOPBITS;
	UartIOCtl(UART_SETSTOPBITS, &uart_param);
	uart_param = UART_DEFAULT_BAUD;
    UartIOCtl(UART_SETSPEED, &uart_param);
	
	UCSRB = BV(RXCIE) | BV(TXCIE) | BV(RXEN) | BV(TXEN);

	fdevopen(UartPutc, UartGetc, 0);
}

void
UartIOCtl(uint16_t req, void *conf)
{
    uint32_t *lvp = (uint32_t *)conf;
    uint32_t lv = *lvp;
    uint8_t bv = (uint8_t)lv;
    uint16_t sv;

    switch (req)
	{
		case UART_SETSPEED:
		{
			sv = (uint16_t) ((((2UL * CPUCLK) / (lv * 16UL)) + 1UL) / 2UL) - 1;
			UBRRL = (uint8_t) sv;
			UBRRH = (uint8_t) (sv >> 8);
		}
        break;

		case UART_GETSPEED:
		{
			sv = ((uint16_t)UBRRH << 8) || UBRRL;
			*lvp = CPUCLK / (16UL * (uint32_t)(sv + 1));
		}
        break;

		case UART_SETDATABITS:
		{
			if (bv >= 5 && bv <= 8)
			{
				bv = (bv - 5) << 1;
				UCSRC = (UCSRC & 0xF9) | bv;
				UCSRB &= 0xFB;
			}
		}
        break;

		case UART_GETDATABITS:
		{
			*lvp = ((UCSRC & 0x06) >> 1) + 5;
		}
        break;

		case UART_SETPARITY:
		{
			if (bv <= 2)
			{
				if (bv == 1) bv = 3;
				bv <<= 4;
				UCSRC = (UCSRC & 0xCF) | bv;
			}
		}
		break;

		case UART_GETPARITY:
		{
			bv = (UCSRC & 0x30) >> 4;
			if (bv == 3) bv = 1;
		}
        break;

		case UART_SETSTOPBITS:
		{
			if (bv == 1 || bv == 2)
			{
				bv = (bv - 1) << 3;
                UCSRC = (UCSRC & 0xF7) | bv;
			}
		}
        break;

		case UART_GETSTOPBITS:
		{
			*lvp = ((UCSRC & 0x08) >> 3) + 1;
		}
        break;
    }
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -