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

📄 uartsw.c

📁 GPS application software. DOC and Source Code
💻 C
字号:
/*! \file uartsw.c \brief Software Interrupt-driven UART Driver. *///*****************************************************************************//// File Name	: 'uartsw.c'// Title		: Software Interrupt-driven UART Driver// Author		: Pascal Stang - Copyright (C) 2002-2004// Created		: 7/20/2002// Revised		: 4/27/2004// Version		: 0.1// Target MCU	: Atmel AVR Series (intended for the ATmega16 and ATmega32)// Editor Tabs	: 4//// This code is distributed under the GNU Public License//		which can be found at http://www.gnu.org/licenses/gpl.txt////*****************************************************************************#include <avr/io.h>#include <avr/interrupt.h>#include <avr/signal.h>#include "global.h"#include "timer.h"#include "uartsw.h"#define inw(sfr) _SFR_WORD(sfr)#define outw(sfr, val) (_SFR_WORD(sfr) = (val)) // Program ROM constants// Global variables// uartsw transmit status and data variablesstatic volatile u08 UartswTxBusy;static volatile u08 UartswTxData;static volatile u08 UartswTxBitNum;// baud rate common to transmit and receivestatic volatile u16 UartswBaudRateDiv;// uartsw receive status and data variablesstatic volatile u08 UartswRxBusy;static volatile u08 UartswRxData;static volatile u08 UartswRxBitNum;// receive bufferstatic cBuffer uartswRxBuffer;               ///< uartsw receive buffer// functions//! enable and initialize the software uartvoid uartswInit(u32 BR){    // initialize the buffers	uartswInitBuffers();	// initialize the ports	sbi(UARTSW_TX_DDR, UARTSW_TX_PIN);	cbi(UARTSW_RX_DDR, UARTSW_RX_PIN);	cbi(UARTSW_RX_PORT, UARTSW_RX_PIN);	// initialize baud rate	uartswSetBaudRate(BR);	// setup the transmitter	UartswTxBusy = FALSE;	// disable OC1A interrupt	cbi(TIMSK1, OCIE1A);	// attach TxBit service routine to OC1A	timerAttach(TIMER1OUTCOMPAREA_INT, uartswTxBitService);	// setup the receiver	UartswRxBusy = FALSE;	// disable OC1B interrupt	cbi(TIMSK1, OCIE1B);	// attach RxBit service routine to OC1B	timerAttach(TIMER1OUTCOMPAREB_INT, uartswRxBitService);	// attach RxBit service routine to ICP	timerAttach(TIMER1INPUTCAPTURE_INT, uartswRxBitService);	// trigger on rising edge	sbi(TCCR1B, ICES1);	// enable ICP interrupt	sbi(TIMSK1, ICIE1);	// turn on interrupts	sei();}//! create and initialize the uart buffersvoid uartswInitBuffers(void){	// initialize the UART receive buffer	bufferInit(&uartswRxBuffer, uartswRxData, UARTSW_RX_BUFFER_SIZE);}//! turns off software UARTvoid uartswOff(void){	// disable interrupts	cbi(TIMSK1, OCIE1A);	cbi(TIMSK1, OCIE1B);	cbi(TIMSK1, ICIE1);	// detach the service routines	timerDetach(TIMER1OUTCOMPAREA_INT);	timerDetach(TIMER1OUTCOMPAREB_INT);	timerDetach(TIMER1INPUTCAPTURE_INT);}void uartswSetBaudRate(u32 baudrate){	// set timer prescaler	timer1SetPrescaler(TIMER_CLK_DIV1);	// calculate division factor for requested baud rate, and set it	UartswBaudRateDiv = (u16)((F_CPU+(baudrate/2L))/(baudrate*1L));}//! returns the receive buffer structure cBuffer* uartswGetRxBuffer(void){	// return rx buffer pointer	return &uartswRxBuffer;}void uartswSendByte(u08 data){	// wait until uart is ready	while(UartswTxBusy);	// set busy flag	UartswTxBusy = TRUE;	// save data	UartswTxData = data;	// set number of bits (+1 for stop bit)	UartswTxBitNum = 9;		// set the start bit	#ifdef UARTSW_INVERT	sbi(UARTSW_TX_PORT, UARTSW_TX_PIN);	#else	cbi(UARTSW_TX_PORT, UARTSW_TX_PIN);	#endif	// schedule the next bit	outw(OCR1A, inw(TCNT1) + UartswBaudRateDiv);	// enable OC1A interrupt	sbi(TIMSK1, OCIE1A);}//! gets a byte (if available) from the uart receive bufferu08 uartswReceiveByte(u08* rxData){	// make sure we have a receive buffer	if(uartswRxBuffer.size)	{		// make sure we have data		if(uartswRxBuffer.datalength)		{			// get byte from beginning of buffer			*rxData = bufferGetFromFront(&uartswRxBuffer);			return TRUE;		}		else		{			// no data			return FALSE;		}	}	else	{		// no buffer		return FALSE;	}}void uartswTxBitService(void){	if(UartswTxBitNum)	{		// there are bits still waiting to be transmitted		if(UartswTxBitNum > 1)		{			// transmit data bits (inverted, LSB first)			#ifdef UARTSW_INVERT			if( !(UartswTxData & 0x01) )			#else			if( (UartswTxData & 0x01) )			#endif				sbi(UARTSW_TX_PORT, UARTSW_TX_PIN);			else				cbi(UARTSW_TX_PORT, UARTSW_TX_PIN);			// shift bits down			UartswTxData = UartswTxData>>1;		}		else		{			// transmit stop bit			#ifdef UARTSW_INVERT			cbi(UARTSW_TX_PORT, UARTSW_TX_PIN);			#else			sbi(UARTSW_TX_PORT, UARTSW_TX_PIN);			#endif		}		// schedule the next bit		outw(OCR1A, inw(OCR1A) + UartswBaudRateDiv);		// count down		UartswTxBitNum--;	}	else	{		// transmission is done		// clear busy flag		UartswTxBusy = FALSE;	}}void uartswRxBitService(void){	// this function runs on either:	// - a rising edge interrupt	// - OC1B	if(!UartswRxBusy)	{		// this is a start bit		// disable ICP interrupt		cbi(TIMSK1, ICIE1);		// schedule data bit sampling 1.5 bit periods from now		outw(OCR1B, inw(TCNT1) + UartswBaudRateDiv + UartswBaudRateDiv/2);		// clear OC1B interrupt flag		sbi(TIFR1, OCF1B);		// enable OC1B interrupt		sbi(TIMSK1, OCIE1B);		// set start bit flag		UartswRxBusy = TRUE;		// reset bit counter		UartswRxBitNum = 0;		// reset data		UartswRxData = 0;	}	else	{		// start bit has already been received		// we're in the data bits				// shift data byte to make room for new bit		UartswRxData = UartswRxData>>1;		// sample the data line		#ifdef UARTSW_INVERT		if( !(inb(UARTSW_RX_PORTIN) & (1<<UARTSW_RX_PIN)) )		#else		if( (inb(UARTSW_RX_PORTIN) & (1<<UARTSW_RX_PIN)) )		#endif		{			// serial line is marking			// record '1' bit			UartswRxData |= 0x80;		}		// increment bit counter		UartswRxBitNum++;		// schedule next bit sample		outw(OCR1B, inw(OCR1B) + UartswBaudRateDiv);		// check if we have a full byte		if(UartswRxBitNum > 8)		{			// save data in receive buffer			bufferAddToEnd(&uartswRxBuffer, UartswRxData);			// disable OC1B interrupt			cbi(TIMSK1, OCIE1B);			// clear ICP interrupt flag			sbi(TIFR1, ICF1);			// enable ICP interrupt			sbi(TIMSK1, ICIE1);			// clear start bit flag			UartswRxBusy = FALSE;		}	}}/*void uartswRxBitService(void){	u16 thisBitTime;	u08 bitperiods;	u08 i;	// bit transition was detected	// record bit's edge time	thisBitTime = inw(ICR1);	cbi(PORTB, 0);	if(!UartswRxStartBit)	{		// this is a start bit		// switch to falling-edge trigger		cbi(TCCR1B, ICES1);		// record bit time		UartswRxBitTime = thisBitTime;		// set start bit flag		UartswRxStartBit = TRUE;		// reset bit counter		UartswRxBitNum = 0;		// reset data		UartswRxData = 0;	}	else	{		// start bit has already been received		// we're in the data bits				// how many bit periods since last edge?		bitperiods = (thisBitTime - UartswRxBitTime + UartswBaudRateDiv/2)/UartswBaudRateDiv;		// set last edge time		UartswRxBitTime = thisBitTime;		if(bitperiods > 10)		{			// switch to trigger on rising edge			sbi(TCCR1B, ICES1);			// clear start bit flag			UartswRxStartBit = FALSE;		}		else		{		if( inb(TCCR1B) & (1<<ICES1) )		{			// just triggered on a rising edge			// previous bits were zero			// shift in the data (data bits are inverted)			for(i=0; i<bitperiods; i++)			{				UartswRxData = UartswRxData<<1;				UartswRxData |= 0x01;			}			// switch to trigger on falling edge			cbi(TCCR1B, ICES1);		}		else		{			// just triggered on a falling edge			// previous bits were one			// shift in the data (data bits are inverted)			for(i=0; i<bitperiods; i++)			{				UartswRxData = UartswRxData<<1;			}			// switch to trigger on rising edge			sbi(TCCR1B, ICES1);		}				// increment bit counter		UartswRxBitNum += bitperiods;				// check if we have a full byte + start bit		if(bitperiods > 8)		{			// save data in receive buffer			bufferAddToEnd(&uartswRxBuffer, UartswRxData);			// switch to trigger on rising edge			sbi(TCCR1B, ICES1);			// clear start bit flag			UartswRxStartBit = FALSE;		}		}	}	// turn off debug LEDs	delay(10);	sbi(PORTB, 0);	sbi(PORTB, 1);}*/

⌨️ 快捷键说明

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