В этом году нашей кафедре выделили деньги на закупку оборудования для обучения и научных исследований. Я заказал стартовый набор от Atmel STK 600. Цена на набор, на мой взгляд, безобразно высока (около 12000 руб).
Вот сам отладочный набор:
stk600 с мезониной платой для 2560
Как видите, на плате разведены все порты, есть диоды и кнопочки. Но в целом, это продвинутый программатор, не поддерживающий отладку по JTAG, что разочаровывает.
К нему я купил россыпь датчиков и LCD дисплей WH1602b. Для этого дисплея есть отличная библиотека WH1602b. Спасибо anterior! Моргать на плате диодами быстро надоело :) Захотелось создать прибор - гигрометр. Для отображения информации использовался WH1602b.Для подключения дисплея к плате был сооружен вот такой шлейф:
шлейф для дисплея
Переменный резистор используется для регулировки контрастности. Питание подсветки индикатора (снизу) организованно по шине USB, так как питания с GND и VCC не хватает. При стандартном напряжении +5В индикатор дико грелся, поэтому пришлось поставить регулируемый резистор для уменьшения напряжения.
Распиновка понятна из кода настроек библиотеки дисплея wh1602b/conf.h:
#define F_CPU 1600000 /* частота мк, Гц */
#define USE_PUTN /* включить поддержку wh1602b_putn() */
#define USE_PUTH /* включить поддержку wh1602b_puth() */
#define USE_GENC /* включить поддержку wh1602b_genc() */
/* ножки к которым подключены выводы RS, RW, EN */
#define NPIN_RS PE0
#define NPIN_RW PE1
#define NPIN_EN PE2
/* порты к которым подключены выводы RS, RW, EN */
#define PORT_RS _SFR_IO_ADDR(PORTE)
#define PORT_RW _SFR_IO_ADDR(PORTE)
#define PORT_EN _SFR_IO_ADDR(PORTE)
#define DDR_RS _SFR_IO_ADDR(DDRE)
#define DDR_RW _SFR_IO_ADDR(DDRE)
#define DDR_EN _SFR_IO_ADDR(DDRE)
/* ножки к которым подключены выводы DB4-DB7 */
#define NPIN_DB7 PE7
#define NPIN_DB6 PE6
#define NPIN_DB5 PE5
#define NPIN_DB4 PE4
/* порты к которым подключены выводы DB4-DB7 */
#define PORT_DB7 _SFR_IO_ADDR(PORTE)
#define PORT_DB6 _SFR_IO_ADDR(PORTE)
#define PORT_DB5 _SFR_IO_ADDR(PORTE)
#define PORT_DB4 _SFR_IO_ADDR(PORTE)
#define DDR_DB7 _SFR_IO_ADDR(DDRE)
#define DDR_DB6 _SFR_IO_ADDR(DDRE)
#define DDR_DB5 _SFR_IO_ADDR(DDRE)
#define DDR_DB4 _SFR_IO_ADDR(DDRE)
Вот код основной программы:
#include <avr/io.h>
#include <stdio.h>
#include <util/delay.h>
#include "wh1602b/wh1602b.h"
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
double humidity = 0;
const double n2 = 1024;
const double Vcc = 5;
const double v_ofset = 0.826;
void init_ADC(void)
{
ADMUX |= (1 << MUX2) | (1 << MUX1) | (1 << MUX0); // порт PF7
ADCSRA |=(1 << ADEN); // ВКЛЮЧИЛИ АЦП
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // ЧАСТОТА ПРЕОБРАЗОВАНИЯ
ADMUX |= (1 << REFS0); // ИСПОЛЬЗУЕТСЯ ОПОРНОЕ НАПРЯЖЕНИЕ AVCC
}
unsigned int read_ADC(void)
{
ADCSRA |= (1 << ADSC); // НАЧАЛО ПРЕОБРАЗОВАНИЯ
_delay_ms(100);
if (ADIF)
{
return ADCW; // виртуальный регистр результатов
}
else
return 0;
}
int main(void)
{
wh1602b_init(); // инициализировать модуль, порты
// настроить параметры управления дисплеем
wh1602b_displayctl(DC_DISPLAY_ON); // дисплей включён
// задать число строк
wh1602b_funcset(FS_LINES_2); // 2 строки
// очистить область
wh1602b_clear();
// вернуться в начало (команда аналогичная move).
// этот вызов является обязательным после вызова genc()
wh1602b_home();
init_ADC();
wh1602b_puts("Please press SW0");
DDRB = 0xff; // все на вывод
DDRD = 0x00; // все на ввод
while ((PIND & (1<<PIND0))); // пока не нажата кнопка 0 ничего не делаем
wh1602b_clear();
wh1602b_puts("Ждите...");
while (1)
{
unsigned int h = 0;
h = read_ADC();
wh1602b_clear();
double u = h*Vcc/n2; // вычисляем напряжение из показаний АЦП, с разрядностью n = 2^10
humidity = (u - 0.826)/0.0315; // из даташита на датчик влажности
wh1602b_puts("Влажность ");
wh1602b_putn(humidity);
wh1602b_puts("%");
wh1602b_move(1,0);
wh1602b_puts("Uвых ");
wh1602b_putn(u*1000);
wh1602b_puts(" мВ");
_delay_ms(50);
}
return 0;
}
#include <avr/io.h>
#include <stdio.h>
#include <util/delay.h>
#include "wh1602b/wh1602b.h"
#include <avr/pgmspace.h>
#include <avr/interrupt.h>
double humidity = 0;
const double n2 = 1024;
const double Vcc = 5;
const double v_ofset = 0.826;
void init_ADC(void)
{
ADMUX |= (1 << MUX2) | (1 << MUX1) | (1 << MUX0); // порт PF7
ADCSRA |=(1 << ADEN); // ВКЛЮЧИЛИ АЦП
ADCSRA |= (1 << ADPS2) | (1 << ADPS1) | (1 << ADPS0); // ЧАСТОТА ПРЕОБРАЗОВАНИЯ
ADMUX |= (1 << REFS0); // ИСПОЛЬЗУЕТСЯ ОПОРНОЕ НАПРЯЖЕНИЕ AVCC
}
unsigned int read_ADC(void)
{
ADCSRA |= (1 << ADSC); // НАЧАЛО ПРЕОБРАЗОВАНИЯ
_delay_ms(100);
if (ADIF)
{
return ADCW; // виртуальный регистр результатов
}
else
return 0;
}
int main(void)
{
wh1602b_init(); // инициализировать модуль, порты
// настроить параметры управления дисплеем
wh1602b_displayctl(DC_DISPLAY_ON); // дисплей включён
// задать число строк
wh1602b_funcset(FS_LINES_2); // 2 строки
// очистить область
wh1602b_clear();
// вернуться в начало (команда аналогичная move).
// этот вызов является обязательным после вызова genc()
wh1602b_home();
init_ADC();
wh1602b_puts("Please press SW0");
DDRB = 0xff; // все на вывод
DDRD = 0x00; // все на ввод
while ((PIND & (1<<PIND0))); // пока не нажата кнопка 0 ничего не делаем
wh1602b_clear();
wh1602b_puts("Ждите...");
while (1)
{
unsigned int h = 0;
h = read_ADC();
wh1602b_clear();
double u = h*Vcc/n2; // вычисляем напряжение из показаний АЦП, с разрядностью n = 2^10
humidity = (u - 0.826)/0.0315; // из даташита на датчик влажности
wh1602b_puts("Влажность ");
wh1602b_putn(humidity);
wh1602b_puts("%");
wh1602b_move(1,0);
wh1602b_puts("Uвых ");
wh1602b_putn(u*1000);
wh1602b_puts(" мВ");
_delay_ms(50);
}
return 0;
}