Наступила очередь рассказать о довольно интересной теме — о том, как подключить AVR микроконтроллер к компьютеру. Для этого, у микроконтроллеров есть приемопередатчик. У некоторых их, даже два.
Update:10.02.17
Использовать будем UART наиболее простой и распространенный интерфейс. Чтобы понять как он работает, представьте себе что уарт это водопроводный кран, из которого течет вода — байты. Каждая новая капля, «затирает» старую, поэтому главная задача нашей программы успевать забирать данные до того, как придут новые.
Существует два основных способа, это все время в цикле проверять наличие новых данных по флагам или настроить прерывание, по приходу нового байта. Если программа не использует задержки и скорость передачи низкая, то можно использовать первый способ, в остальных случаях, лучше использовать прерывания.
Данные приходят последовательно один байт за другим, поэтому часто UART называют последовательным портом. Если ваша программа достаточно простая, то можно принять/передать один байт и на основании этого выполнить какое то действие. Например если приняли байт 100, то включили светодиод.
if(byte == 100) { PORTB.1 = 1; } |
Только не стоит путать ASCII символ и байт, например i = ‘1’ i = 1 не одно и тоже. В чем разница можно почитать тут
Если ваша программа подразумевает, нечто более сложное, т.е. прием нескольких байт, то в прерывании по приходу данных складываем их в массив, далее в основном цикле разбираем массив. Стоит понимать, что поток не имеет ни начала, ни конца, он просто льется постоянно, поэтому нужно самому придумать какие то условности которые бы говорили о том, что сейчас пришел первый байт, а сейчас последний. Типовое решение, это использование спецсимволов, либо таймаутов. Пример можно посмотреть тут
Теперь перейдем к железу. У Atmega8 всего один приемопередатчик, PD0 — Rx, receiver (приемник) и PD1 — Tx, transmitter (передатчик).
Аналогичные ножки есть на нашем переходнике FT232. Соединяем микроконтроллер и переходник между собой. В протеусе это будет выглядеть так:
Напишем программу, которая по сигналу от компьютера будет включать светодиод и выключать. В CodeVision создаем новый проект, микроконтроллер atmega8, частота 8МГц (тактирование от кварца), на закладке USART включаем приемник и передатчик.
Обратите внимание, при текущей частоте микроконтроллера и скорости передачи, ошибка составляет 0,2%, т.е. данные могут теряться, но вероятность этого крайне низкая. Порт B настроим как выход — к нему подключим светодиод.
#include <mega8.h> #include <stdio.h> void main(void) { char data; PORTB=0x00; DDRB=0xFF; PORTD=0x00; DDRD=0x00; // USART initialization // Communication Parameters: 8 Data, 1 Stop, No Parity // USART Receiver: On // USART Transmitter: Off // USART Mode: Asynchronous // USART Baud Rate: 9600 UCSRA=0x00; UCSRB=0x10; UCSRC=0x86; UBRRH=0x00; UBRRL=0x33; while (1) { data=getchar(); if(data=='1') { PORTB=0xFF; } if(data=='0') { PORTB=0x00; } }; } |
В текущем алгоритме используется простой способ функция getchar() постоянно проверяет не появились ли новые данные. После того как данные пришли — записываем их в переменную data; если пришла единичка, зажигаем светодиод; если 0, то выключаем его. Еще раз обратите внимание ‘1’ означает ASCII символ 1, реально байт будет равен 0x31. Сделано так, потому что большинство терминалов при нажатии кнопки на клавиатуре, отправляет именно символы.
Собираем схемку и прошиваем. Подключаем к компьютеру. Запускаем программу KeTerm или другой терминал. Подсоединяемся к нужному com порту. Шлем единичку — светодиод включается, шлем 0 светодиод выключается.
Урок был бы неполным, если не применить наши знания по C#.
Создадим проект, нарисуем 2 кнопки и последовательный порт
В свойствах последовательного порта не забудьте настроить PortName, он должен соответствовать номеру порта переходника FT232. Добавим события: по клику на 1 кнопку — отсылаем 1, по клику на 2 кнопку — отсылаем 0, при загрузке формы — открытие порта, при выходе из формы — закрытие порта.
private void button1_Click(object sender, EventArgs e) { serialPort1.WriteLine("1"); } private void button2_Click(object sender, EventArgs e) { serialPort1.WriteLine("0"); } private void Form1_Load(object sender, EventArgs e) { serialPort1.Open(); } private void Form1_FormClosing(object sender, FormClosingEventArgs e) { serialPort1.Close(); } |
И напоследок, видео работы всего этого безобразия)
Update: По просьбе Евгения программа немного изменена, теперь при запуске программа автоматически проверяет все ком порты, если есть активные, то они заносятся в comboBox1.
1 2 3 4 5 6 | private void Form1_Load(object sender, EventArgs e) { string[] myPort; //создаем массив строк myPort = System.IO.Ports.SerialPort.GetPortNames(); // в массив помещаем доступные порты comboBox1.Items.AddRange(myPort); //теперь этот массив заносим в список(comboBox) } |
Исходники программы
Не пойму как у вас работает ваш пример
while (1)
{
data=UDR;
if(data==’1′)
{
PORTB=0xFF;
}
if(data==’0′)
{
PORTB=0x00;
}
};
Отправляю через Vb.net 0 или 1 не чего не срабатывает. Какой та бред с кодировкой
попробуйте просто через терминал слать байты
❓ Вопрос: как написать программу на делфи и на Си++ выполняющие такие же функции. и еще как читать данные через программу
А каким образом передавать с МК? Можете написать фрагмент кода, именно касающийся к передаче. За ранее благодарен
printf(«hello»); отправляет форматированную строку hello
а как эту программу написать не на СИ а на асемблере?
в даташите есть примеры, названия регистров не отличаются, так что суть таже самая
как вывести данные на компоненте listbox из COM-порта? Почему-то строка ниже не работает
listBox1.Items.Add(serialPort1.ReadLine());
а если так
listBox1.Items.Add(serialPort1.ReadLine().ToString());
Сделал абсолютно то же самое, только контроллер у меня ATmega 8535. Тоже пользовался кодеВижн и С#. Пробовал из терминала слать цифры 1, 2 и т. д. Ничего не срабатывает. Программа на С# также не работает. Пробовал по другому, PORTC=UDR. Т. е. у меня на порт С идет то что пришло с компа. На каждой ноге порта С по диоду. Вот так работает. В термииле кидаю разные числа — диоды загораются. Хотя системы никакой нет.
Была проблема, что нужно не просто писать serialPort1.Write(«0») а именно serialPort1.WriteLine(«0»)
В программе для компьютера на C# предлагаю усовершенствовать процедуру открытия порта:
private void button3_Click(object sender, EventArgs e)
{
serialPort1.BaudRate = 9600;
serialPort1.PortName = comboBox1.Text.ToString();
try
{
if (serialPort1.IsOpen == false)
serialPort1.Open();
}
catch
{
MessageBox.Show(«Порт занят»);
}
}
По хорошему, да, нужно обрабатывать исключения
Огромное спасибо автору. Повторил эксперимент. Использовал для связи max232/
скажите а нужен ли для этого урока внеший кварц???
желательно
Здраствуйте Админ. Сайт очень прилесный вот хотел попросить вас, сделать хоть один урок на тему контроллера и Wi-Fi модулей и передача данных через модуль Wi-Fi. С Уважением ваш постоянный читатель сайта.
hoy, без внешнего кварца, лично у меня, ничего не работало, поставил и тут же заработало
а подскажите на какой максимальной скорости вообще можно организовать обмен данными?
и что если использовать не ft232 а например max232, скорость как то изменится?
Потолок ограничен скоростью микроконтроллера, еще не забывайте что чем больше скорость тем больше ошибок. Обычно потолок 115200*2, т.е. примерно 20кБ/c
А какое практическое применение всего этого?
как адрес прописать тут микроконтроллера rs485 можно вешать несколько устройств! у меня ПК и 2 микрконтр. как то одному отсылать то другому ?
Передать данные между разными устройствами
Сделайте условие, если пришел 1 байт — делать то то, если другой, делать другое. if(received_byte[0]==’x’){…}
Большая просьба, расскажите про работу rs232 в windows forms — какие функции от куда берутся?
как принимать и обрабатывать принятую информацию в windows forms?
здравствуйте. подскажите что не правильно написано. в протеусе всё работает а в живую нет
#include
#include
interrupt [USART_RXC] void usart_rx_isr(void)
{
char data;
data=UDR;
if (data==’1′)
{
PORTB.0=1;
}
if (data==’0′)
{
PORTB.0=0;
}
if (data==’2′)
{
PORTB.1=1;
}
if (data==’3′)
{
PORTB.1=0;
}
}
void main(void)
{
PORTB=0x00;
DDRB=0xFF;
UCSRA=0x00;
UCSRB=0x90;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x33;
#asm(«sei»)
while (1)
{
}
}
ничего необычного вроде нет, смотрите кварц, настройки, схему
#include (mega32.h)
#include (stdio.h)
interrupt [USART_RXC] void usart_rx_isr(void)
{
char data;
data=UDR;
if (data==’1′)
{
PORTB.0=1;
}
if (data==’0′)
{
PORTB.0=0;
}
if (data==’2′)
{
PORTB.1=1;
}
if (data==’3′)
{
PORTB.1=0;
}
}
void main(void)
{
PORTB=0x00;
DDRB=0xFF;
UCSRA=0x00;
UCSRB=0x90;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x33;
#asm(«sei»)
while (1)
{
}
}
нужно использовать внешний кварц на mega32 к написанному выше?
естественно, может заработать и без него, но вероятность этого не высока
спасибо большое
поставил кварц на 10 MHz один хрен что-то не то. не работает. может быть в visual studio что то не правильно. хотя на Модуле FT232 промаргивает лампочка TX.
Под каждую частоту свои настройки юарта, перегенерите мастером под 10МГц и начните с проверки в терминале.
У меня програмка для МК начала работать только после того как , принимаемые данные
записал в шестнадцатиричном коде таблицы ASCII т.е.
if (data == 0x30) {PORTB = 0x00};
if (data == 0x31) {PORTB = 0xFF};
Кварц не использовал , всё работает без него .
Обновлено
А на какое расстояние можно организовать передачу данных?
Я хочу подать 0 или 1 на диод, через порт С, с помощью virtual terminal. Почему ничего не срабатывает &
#include
void main(void)
{
char date=0;
PORTC=0x00;
DDRC=0x01;
UCSRA=0x00;
UCSRB=0x18;
UCSRC=0x86;
UBRRH=0x00;
UBRRL=0x33;
while (1)
{
date=UDR;
if (date==’1′) PORTC.0=1;
if (date==’0′) PORTC.0=0;
}
}
Зависит от того как будет организован физический канал(железо).
принимайте через date=getchar();