ATTINY13 ADC-UART

Трёхканальный АЦП выполнен на микроконтроллере ATTINY13 и передаёт данные один раз в секунду через программный UART на скорости 9600 бод. Данные приходят в шестнадцатиричном виде, каждый канал разделяется пробелом, после чего следует конец строки \r\n.


Перевод в напряжение производится по формуле:
R*(Uоп/1024)*ADC
Где R — коэффициент делителя, по схеме равен 11(С моими резисторами вышел 11,1);
Uоп — опорное напряжение;
ADC — код АЦП.
У меня получился делитель 11,1, опорное 3,3В и код АЦП 008B. Вход был подключен к питание Orange Pi Zero.
11.1*(3.3/1024)*0x8b=4.97В.

Схема — проще не бывает:

Конденсаторы лучше использовать керамические 1206 X7R. Я ставил X5R и только С1. С2 решил не ставить, так как недалеко есть на Orange Pi. Так же сэкономил на R7, что нежелательно. Резисторы R8 и R9 ставить не обязательно, они на будущее. Планирую вариант с i2c, если получится.
Плата 20х35мм была сделана в SprintLayout, так как схема не предполагалась и чертил её позже для этой статьи.

#define F_CPU 9600000UL

#include <avr/io.h>
#include <util/delay.h>
#include <avr/interrupt.h>

#define delay 98    //Задержка для 9600 бод
void USART_Init(void)
{
	DDRB|=1<<0;
	PORTB|=(1<<0);
}

void USART_Transmit(char data)
{
	uint8_t i;
	_delay_ms(1);
	PORTB&=~(1<<0);
	_delay_us(delay);
	
	for(i=0; i<8; i++)
	{
		if((data&(1<<i))!=0)
		{
			PORTB|=(1<<0);
		}
		else
		{
			PORTB&=~(1<<0);
		}
		_delay_us(delay);
		
	}
	PORTB|=(1<<0);
}

void USART_TransmitStr(char *data)
{
	uint8_t i=0;
	while(data[i])
	{
		USART_Transmit(data[i]);
		i++;
	}
}

void USART_Transmit_16(uint8_t data)
{
	uint8_t a,b;
	a=data>>4;
	if(a>9)a+=7;
	b=data<<4;
	b=b>>4;
	if(b>9)b+=7;
	USART_Transmit(a+48);
	USART_Transmit(b+48);
}

void ADC_Init(void)
{
	ADMUX = 0;				//Взять опорное напряжение для АЦП от вывода питания
	//~ ADMUX = (1<<REFS0);			//Взять опорное от внутреннего источника
	ADCSRA = (1<<ADPS1) | (1<<ADPS0);
	ADCSRA |= (1<<ADEN);
	ADCSRA |= (1<<ADSC);
	while (ADCSRA & (1<<ADSC) ) {}
	(void) ADCW;
}

uint16_t ADC_Read( uint8_t channel )
{
	ADMUX = (ADMUX & ~(0x1F)) | (channel & 0x1F);
	ADCSRA |= (1<<ADSC);
	while (ADCSRA & (1<<ADSC) ) {}
	return ADCW;
}

uint16_t ADC_Read_Avg(uint8_t channel, uint8_t nsamples)
{
	uint32_t sum = 0;
	for (uint8_t i = 0; i<nsamples; ++i) 
	{
		sum += ADC_Read(channel);
	}
	return (uint16_t)(sum/nsamples);
}

int main (void)
{
	uint16_t adc;
	char i;
	ADC_Init();
	USART_Init();
	while(1)
	{
		for(i=1; i<4;i++)
		{
			adc=ADC_Read_Avg(i,5);			//Считать данные с канала
			USART_Transmit_16(adc>>8);		//Передать старшие 8 бит данных
			USART_Transmit_16((uint8_t)adc);	//Передать младшие 8 бит данных
			USART_TransmitStr(" ");
		}
		USART_TransmitStr("\r\n");
		_delay_ms(1000);
	}
}

Скрипт на python, необходимо установить python-serial.

#!/usr/bin/python   
import serial
ser = serial.Serial("/dev/ttyS1", 9600, timeout=1)

while(1):
        line = ser.readline()
        lenstr = len(line)
        if lenstr >= 5:
                hex1=line[0:4]
                hex2=line[5:9]
                hex3=line[10:14]
                adc1=int(line[0:4], 16)
                adc2=int(line[5:9], 16)
                adc3=int(line[10:14], 16)
                U1=11.4*(3.3/1024)*adc1
                U2=11.4*(3.3/1024)*adc2
                U3=11.4*(3.3/1024)*adc3
                print(str(round(U1,2))+" "+str(round(U2,2))+" "+str(round(U3,2)))

Схема(DipTrace), прошивка(Си и hex) и чертёж платы(lay6).

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *