git-svn-id: http://moon:8086/svn/projects/HendiControl@11 fda53097-d464-4ada-af97-ba876c37ca34
332 lines
6.3 KiB
C
Executable File
332 lines
6.3 KiB
C
Executable File
/*
|
||
* uart_echo.c
|
||
*
|
||
* Created: 16.08.2018 17:39:49
|
||
* Author : jens
|
||
*/
|
||
|
||
#include <stdio.h>
|
||
#include <avr/io.h>
|
||
#include <avr/interrupt.h>
|
||
#define ARDUINO_NANO
|
||
|
||
#ifdef ARDUINO_NANO
|
||
#define F_CPU (16000000UL) // MHz
|
||
#else
|
||
#define F_CPU (18432000UL) // MHz
|
||
#endif
|
||
#define USART_BAUDRATE 9600UL
|
||
#define BAUD_PRESCALE (((F_CPU / (USART_BAUDRATE * 16UL))) - 1)
|
||
#define TIMER_RELOAD (0xFFFF-(F_CPU/1024/4-1))
|
||
static uint8_t rx_data;
|
||
static uint8_t count = 0;
|
||
volatile uint8_t msgCode = 0;
|
||
static uint8_t msgData = 0;
|
||
static uint8_t ledState = 0;
|
||
static int16_t adc_value[16];
|
||
static size_t adc_ch = 0;
|
||
|
||
enum MessageCode
|
||
{
|
||
NOP=0,
|
||
Command,
|
||
Timer,
|
||
AdcComplete,
|
||
Error = 0xFF
|
||
};
|
||
|
||
ISR(ADC_vect)
|
||
{
|
||
int16_t value_low = (int16_t)ADCL;
|
||
int16_t value_high = (int16_t)ADCH;
|
||
ADCSRA |= (1<<ADIF);
|
||
int16_t value = value_high << 8 | value_low;
|
||
|
||
if (((adc_value[adc_ch] - value) < -1) || ((adc_value[adc_ch] - value) > 1))
|
||
{
|
||
msgCode = AdcComplete;
|
||
msgData = adc_ch;
|
||
}
|
||
|
||
adc_value[adc_ch] = value;
|
||
adc_ch++;
|
||
if (adc_ch == 16)
|
||
{
|
||
adc_ch = 0;
|
||
}
|
||
adc_start_conversion(adc_ch);
|
||
}
|
||
|
||
ISR(USART_RX_vect)
|
||
{
|
||
rx_data = UDR0;
|
||
|
||
msgCode = NOP;
|
||
if (rx_data == ' ')
|
||
{
|
||
msgCode = Error;
|
||
}
|
||
else if (rx_data >= '0' && rx_data <= '9')
|
||
{
|
||
msgCode = Command;
|
||
msgData = rx_data;
|
||
}
|
||
count++;
|
||
}
|
||
|
||
ISR (TIMER1_OVF_vect) // Timer1 ISR
|
||
{
|
||
msgCode = Timer;
|
||
TCNT1 = TIMER_RELOAD;
|
||
ledState++;
|
||
if (ledState == 4)
|
||
{
|
||
ledState = 0;
|
||
}
|
||
}
|
||
|
||
void uart_init()
|
||
{
|
||
// Set baud rate
|
||
UBRR0L = (uint8_t)BAUD_PRESCALE;
|
||
UBRR0H = (uint8_t)(BAUD_PRESCALE >> 8);
|
||
|
||
// Enable receiver and transmitter
|
||
UCSR0B = (1<<TXEN0)|(1<<RXEN0);
|
||
|
||
// Enable RX interrupt
|
||
UCSR0B |= (1<<RXCIE0);
|
||
|
||
}
|
||
|
||
void timer_init()
|
||
{
|
||
|
||
TCNT1 = TIMER_RELOAD;
|
||
|
||
TCCR1A = 0x00;
|
||
TCCR1B = (1<<CS10) | (1<<CS12); // Timer mode with 1024 prescaler
|
||
TIMSK1 = (1 << TOIE1) ; // Enable timer1 overflow interrupt(TOIE1)
|
||
|
||
}
|
||
|
||
enum I2C
|
||
{
|
||
I2C_START = 0x08,
|
||
I2C_REPEATED_START = 0x10,
|
||
I2C_SLA_ACK = 0x18,
|
||
I2C_SLA_NACK = 0x20,
|
||
I2C_DATA_ACK = 0x28,
|
||
I2C_DATA_NACK = 0x30,
|
||
I2C_LOST = 0x38,
|
||
I2C_READ = 0x01,
|
||
I2C_WRITE = 0x00
|
||
};
|
||
|
||
void i2c_init()
|
||
{
|
||
TWBR = 0xFF;
|
||
TWSR = 0x03;
|
||
}
|
||
|
||
void i2c_send(uint8_t addr, uint8_t rw, uint8_t *data, size_t size)
|
||
{
|
||
TWCR = (1<<TWINT)|(1<<TWSTA)|(1<<TWEN);
|
||
// Send START condition
|
||
do
|
||
{
|
||
while (!(TWCR &(1<<TWINT))); // Wait for TWINT Flag set. This indicates
|
||
// that the START condition has been
|
||
// transmitted.
|
||
if((TWSR & 0xF8) != I2C_START)
|
||
{
|
||
printf("Error I2C_START\n");
|
||
break;
|
||
}
|
||
TWDR = addr<<1 | rw; // Load SLA_W into TWDR Register. Clear
|
||
// TWINT bit in TWCR to start transmission of
|
||
// address.
|
||
TWCR = (1<<TWINT) | (1<<TWEN);
|
||
while (!(TWCR &(1<<TWINT))); // Wait for TWINT Flag set. This indicates
|
||
// that the SLA+W has been transmitted, and
|
||
// ACK/NACK has been received.
|
||
|
||
|
||
if ((TWSR & 0xF8) != I2C_SLA_ACK)
|
||
{
|
||
printf("Error I2C_SLA_ACK\n");
|
||
break;
|
||
}
|
||
// Check value of TWI Status Register. Mask
|
||
// prescaler bits. If status different from
|
||
// MT_SLA_ACK go to ERROR
|
||
for (size_t i=0; i < size; i++)
|
||
{
|
||
|
||
TWDR = *(data++);
|
||
TWCR = (1<<TWINT) | (1<<TWEN);
|
||
// Load DATA into TWDR Register. Clear
|
||
// TWINT bit in TWCR to start transmission of
|
||
// data.
|
||
|
||
while (!(TWCR & (1<<TWINT)));
|
||
// Wait for TWINT Flag set. This indicates
|
||
// that the DATA has been transmitted, and
|
||
// ACK/NACK has been received}
|
||
|
||
if ((TWSR & 0xF8) != I2C_DATA_ACK)
|
||
{
|
||
printf("Error I2C_DATA_ACK\n");
|
||
break;
|
||
}
|
||
// Check value of TWI Status Register. Mask
|
||
// prescaler bits. If status different from
|
||
// MT_DATA_ACK go to ERROR.
|
||
}
|
||
|
||
} while (0);
|
||
TWCR = (1<<TWINT)| (1<<TWEN)|(1<<TWSTO); // Transmit STOP condition.
|
||
|
||
}
|
||
|
||
void adc_init()
|
||
{
|
||
PRR &= ~(1 << PRADC);
|
||
ADCSRA |= (1 << ADEN) | 7;
|
||
}
|
||
|
||
void adc_start_conversion(int ch)
|
||
{
|
||
ADMUX = (ADMUX & 0xF0) | (ch & 0x0F) | (1 << REFS0);
|
||
ADCSRA |= (1 << ADSC) | (1 << ADIE);
|
||
}
|
||
|
||
int adc_is_fininshed()
|
||
{
|
||
return (int)(0 == (ADCSRA & (1 << ADSC)));
|
||
}
|
||
|
||
int16_t adc_read()
|
||
{
|
||
return adc_value;
|
||
|
||
while(!adc_is_fininshed());
|
||
uint16_t value_low = (uint16_t)ADCL;
|
||
uint16_t value_high = (uint16_t)ADCH;
|
||
ADCSRA |= (1<<ADIF);
|
||
return value_high << 8 | value_low;
|
||
}
|
||
|
||
void uart_putc(char c)
|
||
{
|
||
while((UCSR0A & (1<<UDRE0)) == 0)
|
||
{
|
||
}
|
||
UDR0 = c;
|
||
}
|
||
|
||
int uart_putchar(char c, FILE *stream)
|
||
{
|
||
uart_putc(c);
|
||
if (c == 0x0A)
|
||
{
|
||
uart_putc(0x0D);
|
||
}
|
||
return 0;
|
||
}
|
||
|
||
void uart_puts(char const *str)
|
||
{
|
||
while(*str)
|
||
{
|
||
char c = *(str++);
|
||
uart_putc(c);
|
||
if (c == 0x0A)
|
||
{
|
||
uart_putc(0x0D);
|
||
}
|
||
}
|
||
}
|
||
|
||
void port_init()
|
||
{
|
||
PORTB = PORTB | 0x03;
|
||
DDRB = DDB1 | DDB2;
|
||
|
||
}
|
||
FILE uart_file = FDEV_SETUP_STREAM(uart_putchar, NULL, _FDEV_SETUP_WRITE);
|
||
|
||
|
||
int main(void)
|
||
{
|
||
|
||
/* Replace with your application code */
|
||
uart_init();
|
||
timer_init();
|
||
adc_init();
|
||
i2c_init();
|
||
|
||
stdout = &uart_file;
|
||
printf("UART test version 1.0\n\n");
|
||
|
||
uint8_t write_dac_full[] = {0x40, 0x00, 0x00}; // 6.1 Write Volatile DAC Register (C2:C0 = ‘00x’)
|
||
i2c_send(0x60, I2C_WRITE, write_dac_full, sizeof(write_dac_full));
|
||
|
||
sei();
|
||
adc_start_conversion(adc_ch);
|
||
while (1)
|
||
{
|
||
|
||
if (msgCode)
|
||
{
|
||
cli();
|
||
uint8_t _msgCode = msgCode;
|
||
uint8_t _msgData = msgData;
|
||
sei();
|
||
|
||
switch(_msgCode)
|
||
{
|
||
case Command:
|
||
printf("Command : %c\n", _msgData);
|
||
uint8_t write_dac[] = {0x00+(_msgData-'0'), 0x00}; // 6.2 Write Volatile Memory (C2:C0 = ‘010’)
|
||
i2c_send(0x60, I2C_WRITE, write_dac, sizeof(write_dac));
|
||
break;
|
||
|
||
case AdcComplete:
|
||
{
|
||
size_t ch = _msgData;
|
||
if (ch == 6)
|
||
{
|
||
printf("ADC=%d\n", adc_value[ch]);
|
||
}
|
||
}
|
||
break;
|
||
|
||
case Timer:
|
||
switch(ledState)
|
||
{
|
||
case 0:
|
||
DDRB = (DDRB & 0xFC) | 0x00;
|
||
printf("----------- Timer -----------\n");
|
||
break;
|
||
case 1:
|
||
DDRB = (DDRB & 0xFC) | 0x01;
|
||
break;
|
||
case 2:
|
||
DDRB = (DDRB & 0xFC) | 0x03;
|
||
break;
|
||
case 3:
|
||
DDRB = (DDRB & 0xFC) | 0x02;
|
||
break;
|
||
}
|
||
break;
|
||
|
||
case Error:
|
||
printf("Error!!!\n");
|
||
break;
|
||
}
|
||
}
|
||
}
|
||
}
|
||
|