summaryrefslogtreecommitdiffstats
path: root/Soft_UART_Timer1.h
blob: 4ad86690708d4a61e79fbe5eae05f3d20d877e3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
/*
 * Soft_UART_Timer1.h
 *
 * Software UART for ATmega328p using Timer1
 * 
 * Now only tranmission, no receiving
 */ 

#ifndef SOFTUARTTIMER1_H_
#define SOFTUARTTIMER1_H_

//////////////////////////////////////////////////////////////////////////
// Usage (in your .c file):
// 1. define Tx pin: DDR register, PORT register, PIN number:
// #define Soft_UART_TX_PORT PORTD
// #define Soft_UART_TX_DDR DDRD
// #define Soft_UART_TX_PIN 3
// 2. define UART speed
// #define Soft_UART_Baud 9600
// 3. include .h file:
// #include "Soft_UART_Timer1.h"
// 3. initialize software UART, required to call before usage other functions:
// static void Soft_UART_init(void);
// 4. send byte
// static void Soft_UART_send_byte(char byte);
// this function send byte in background,
// only one byte in background, other will wait.
//////////////////////////////////////////////////////////////////////////


//////////////////////////////////////////////////////////////////////////
// From this line begins code to the end of file.
// All code written in .h file for better inline optimization.
// Try to include this file only once per project.
//////////////////////////////////////////////////////////////////////////

volatile char Soft_UART_busy_flag=0;
char Soft_UART_next_byte=0;

//////////////////////////////////////////////////////////////////////////
// Initialization software UART, required to call before usage
//////////////////////////////////////////////////////////////////////////
static void Soft_UART_init(void)
{   // Pin init
	bit_set(Soft_UART_TX_DDR,Soft_UART_TX_PIN);
	bit_set(Soft_UART_TX_PORT,Soft_UART_TX_PIN);
	// Timer1 init
	TCCR1A=(0<<COM1A1)|(0<<COM1A0)|(0<<COM1B1)|(0<<COM1B0)|(1<<WGM11)|(0<<WGM10);
	TCCR1B=(0<<ICNC1)|(0<<ICES1)|(1<<WGM13)|(1<<WGM12)|(0<<CS12)|(0<<CS11)|(0<<CS10); // prescaler 0, timer stopped
	TCCR1C=(0<<FOC1A)|(0<<FOC1B);
	TIMSK1=(0<<ICIE1)|(0<<OCIE1B)|(0<<OCIE1A)|(0<<TOIE1);
	//ICR1=1666;
	ICR1=F_CPU/Soft_UART_Baud;
}

//////////////////////////////////////////////////////////////////////////
// Internal function, start timer, when need to send something
//////////////////////////////////////////////////////////////////////////
static void Soft_UART_Timer1_start(void)
{
	bit_set(TIMSK1,TOIE1);
	bit_set(TCCR1B,CS10);
}

//////////////////////////////////////////////////////////////////////////
// Internal function, stop timer, when nothing to send
//////////////////////////////////////////////////////////////////////////
static void Soft_UART_Timer1_stop(void)
{
	bit_clr(TIMSK1,TOIE1);
	bit_clr(TCCR1B,CS10);
}

//////////////////////////////////////////////////////////////////////////
// Send byte in background, only one byte in background, other - wait
//////////////////////////////////////////////////////////////////////////
static void Soft_UART_send_byte(char byte)
{
	while(Soft_UART_busy_flag)
		;
	Soft_UART_busy_flag=1;
	Soft_UART_Timer1_start();
	Soft_UART_next_byte=byte;
}

//////////////////////////////////////////////////////////////////////////
// Internal function, send next bit
//////////////////////////////////////////////////////////////////////////
ISR(TIMER1_OVF_vect)
{
	static char Soft_UART_pos=0;
	switch(Soft_UART_pos)
		{
			case 0: // send START bit
					bit_clr(Soft_UART_TX_PORT,Soft_UART_TX_PIN);
					break;
			case 9:	// send STOP bit
					bit_set(Soft_UART_TX_PORT,Soft_UART_TX_PIN);
					break;
			case 10:// end of transmission
					Soft_UART_busy_flag=0;
					Soft_UART_pos=0;
					Soft_UART_Timer1_stop();
					return;
			default:// send data bit
					if(bit_tst(Soft_UART_next_byte,Soft_UART_pos-1))
						bit_set(Soft_UART_TX_PORT,Soft_UART_TX_PIN);
					else
						bit_clr(Soft_UART_TX_PORT,Soft_UART_TX_PIN);
					break;
		}
	Soft_UART_pos++;
	bit_change(PORTB,5);
}
#endif /* SOFTUARTTIMER1_H_ */