Главная » Статьи » Полезная информация

Управляем микроконтроллером с ПК по UART

Задача
Есть схема со светодиодом и подключением к компьютеру по UART. На компьютере должна быть программа позволяющая зажигать и гасить светодиод на плате с микроконтроллером. Также неплохо было бы если в компьютерной программе имелась возможность принимать сообщения от микроконтроллера.

Реализация
Программа для микроконтроллера как и всегда будет написана в Bascom-AVR. А вот для ПК я никогда не программировал, поэтому решил пойти по пути наименьшего сопротивления и выбрал компилятор Basic-подобного языка - PureBasic.  После вводной статьи от товарища  Aleks8383 про его USB-вольтметр, PureBasic показался мне не сложным. Поэтому решил остановится на нем. 


Тестовая схема собрана на микроконтроллере ATMega8. Можно обойтись без кварца, просто на макетке он у меня стоит, поэтому задействовал. С компьютером схема соединяется через любой имеющийся преобразователь, я использую USB-UART на микросхеме FT232RL. 




Программа для микроконтроллера в Bascom-AVR.

$regfile = "m8def.dat"
$crystal = 12000000
$baud = 19200

Config Portb.= Output                     'подключаем светодиод
Led Alias Portb.0

'объявляем подпрограммы
Declare Sub Getline(As String)            'чтение данных из буфера
Declare Sub Del_buffer()                    'очистка буфера

Dim R As Byte
Dim S As String * 1
Dim B As Byte

Do
= Ischarwaiting()     'проверка наличия команды в буфере UART
 If R = 1 Then          'если в буфере что-то есть переменной R присвоится значение 1
  Getline S             'вытаскиваем содержимое буфера в переменную S
   If S = "A" Then      'если там символ "А"
    Print "Led ON"      'отошлем сообщение
    Led = 1             'и включим светодиод
   Elseif S = "B" Then  'если там символ "В"
    Print "Led OFF"     'сообщим о выключении
    Led = 0             'выключаем светодиод
   End If
  Del_buffer            'если в буфере что-то другое очищаем его
 End If
Loop
End

'подпрограмма для разбора сообщения c UART
'=========================================
Sub Getline(As String)
= ""
Do
 B = Inkey()                              'берем символ из буфера в формате ASCII
 Select Case B
  Case 0 : Exit Do                        'если дальше буфер пуст - выходим из цикла
  Case 10 : If S <> "" Then Exit Do       'конец строки, значит выходим из цикла
  Case Else : If B > 31 Then S = S + Chr(b)    'составляем строку 
 End Select
Loop
End Sub

'очистка буфера UART
'===================
Sub Del_buffer()
 Do
 B = Inkey()               'кладем в переменную "В" данные из буфера
 Loop Until B = 0          'выходим из цикла когда в переменную попадет 0 (буфер пуст)
End 
Sub

Немного поясню программу. 
Функция Ischarwaiting() возвратит переменной R единицу если в буфере присутствуют какие-либо данные. Если функция вернула единицу идем в подпрограмму Getline и кладем в переменную S все что прочитали из буфера. В этой самой подпрограмме Sub Getline в цикле Do...Loop  по одному достаются значения символов согласно таблице ASCII с помощью функции Inkey()
Тут надо остановится и сказать что по таблице ASCII до 31 значения идут управляющие символы. Так цифра 10 означает завершение строки (Line Feed), это то чем завершается строка и обнаружив ее мы завершаем извлекать данные из буфера и уходим из цикла.  А все печатаемые символы (буквы и цифры) имеют значения больше 31. 
Поэтому если в переменную В попадает значение больше 31 значит этот символ добавляем в основную строку = S + Chr(b)
Если все данные из буфера мы достали, а символа 10 так и не дождались (если программа или устройство по какой-то причине автоматически не завершает строку) то из цикла нам поможет выйти свойство функции Inkey() , она в случае пустого буфера возвращает 0. По этому условию у нас тоже организован выход из цикла.

 Так как из-за помех в буфер может попасть какой-нибудь мусор, аналогичным образом организована подпрограмма очистки буфера Sub Del_buffer().  К ней мы можем обращаться каждый раз после чтения, чтобы исключить порчу строк ненужными данными. 

 А дальше, получив строку S, в зависимости от ее содержимого, выполняем определенное действие. К примеру если пришел символ "А" - включим светодиод, если "В" - выключим.

 Теперь перейдем на приложение со стороны компьютера. Программа для ПК написанная в PureBasic:

#COM_Port = 2 ;Идентификатор COM порта. 
;Процедура открытия порта. выбранного из списка
Procedure Select_ComPort() 
 Protected Port.s, Text.s, Color 
 
If IsSerialPort(#COM_Port) ;С таким ИД уже открыт порт. 
 CloseSerialPort(#COM_Port)  ;Закрываем его. 
EndIf 
 
Port = GetGadgetText(3) ;Тут открываем порт с необходимыми настройками
If OpenSerialPort(#COM_Port,Port,19200,#PB_SerialPort_NoParity,8,1,#PB_SerialPort_NoHandshake,255,255) 
Text="Порт "+Port+" открыт" : Color=RGB(46, 137, 36) 
Else 
 Text="Не удалось открыть порт "+Port : Color=RGB(255,0,0) 
EndIf 
 SetGadgetText(5, Text) 
 SetGadgetColor(5, #PB_Gadget_FrontColor, Color) 
EndProcedure 
;Процедура приема данных
Procedure InData()   
 Protected InBytes 
 
 If IsSerialPort(#COM_Port)  ;С таким ИД порт открыт. 
 InBytes = AvailableSerialPortInput(#COM_Port) 
 If InBytes>0  ;Получены данные. 
 Protected Dim InBuffer.a(InBytes), RealInBytes 
 
 RealInBytes = ReadSerialPortData(#COM_Port, @InBuffer(), InBytes) 
 If RealInBytes>0 
 AddGadgetItem(4, -1, PeekS(@InBuffer(), RealInBytes, #PB_Ascii)) 
 EndIf 
 EndIf 
 EndIf 
EndProcedure 

;Процедура передачи данных
Procedure ComOut(Send_data.s)  
 
 If IsSerialPort(#COM_Port) ;если порт открыт 
 ComWrite(SerialPortID(#COM_Port),@send_data,1) ;Шлем данные из переменной Send_data 
 Else 
 ;Выводим сообщение об ошибке. 
 MessageRequester("Ошибка","Текущий порт не доступен!",16) 
 EndIf 
 
EndProcedure 

If OpenWindow(0, 300, 100, 320, 370, "Тестовая программа") ;Создаем окно программы
 ButtonGadget(1, 90, 310, 100, 35, "Зажечь", #PB_Button_Default) ;Кнопка "Зажечь"
 TextGadget(2,10,310,25,15,"Порт") ;Выводим в окно надпись "Порт". 
 ComboBoxGadget(3, 10, 325, 70, 21, #PB_ComboBox_Editable) ;гаджет выпадающего списка
 For i=1 To 99 ;создаем список от 1 до 99 с возможными портами для открытия
 AddGadgetItem(3,-1,"COM"+Str(i)) 
 Next i 
 
 SetGadgetState(3,0) ;Делаем активным нулевой пункт выпадающего списка. 
 EditorGadget(4, 8, 10, 305, 280,#PB_String_ReadOnly) 
 TextGadget(5,10,350,200,15,"")  ;Здесь будет отображаться результат открытия порта. 
 ButtonGadget(6, 200, 310, 100, 35, "Погасить", #PB_Button_Default) ;Кнопка "Погасить"
 Select_ComPort() 
 
 Repeat 
 
 Event = WaitWindowEvent() 
 
 InData()  ;принимаем данные из UART все время пока работает программа
  If Event=#PB_Event_Gadget  ;если произошло срабатывание гаджета 
 Gadget = EventGadget ( )  ;узнаем какой гаджет был активирован 
 If Gadget=1  ;если нажата кнопка "Зажечь" 
 ComOut("A")  ;Переходим на процедуру передачи байта. 
 InData() 
 ElseIf Gadget=3  ;если был активирован выпадающий список
 ComboBox.s=GetGadgetText(3)  ;Считываем текст из текущего пункта выпадающего списка. 
 ; Переходим на процедуру, закрывающую текущий порт и открывающую выбранный. 
 Select_ComPort() 
 
 ElseIf Gadget=6  ;нажата кнопка "Погасить" 
 ComOut("B")  ;Переходим на процедуру передачи байта. 
 InData() 
 
 EndIf 
 EndIf 
 
 Until Event=#PB_Event_CloseWindow 
 
EndIf 
End 

 В начале программы присутствуют три процедуры:
 Procedure Select_ComPort() - процедура открытия выбранного из списка COM-порта. При срабатывании гаджета ComboBoxGadget произойдет выбор номера порта и этот номер будет открыт (если доступен) в данной процедуре. Здесь же прописываются необходимые настройки порта (скорость, размер буфера и пр.) так же нужно не забывать что микроконтроллер и программа должны общаться на одной скорости. В данном примере использую скорость 19200 бод.
 Procedure InData() - процедура чтения данных из ком-порта. Этой процедурой пользуемся когда нужно узнать что пришло от микроконтроллера. Прочитанные данные помещаются в гаджет под номером 4 (у нас это EditorGadget)
 Procedure ComOut(Send_data.s) - процедура отправки данных в ком-порт. Отправляться будет содержимое переменной Send_data. 

 А дальше в программе  идут стандартные функции создания окна и необходимых гаджетов
OpenWindow(0, 300, 100, 320, 370, "Тестовая программа") ;Создаем окно программы
и обработка их действий
Event = WaitWindowEvent()

 В результате программа обзаведется двумя кнопками ("Зажечь" и "Погасить"), выпадающим списком, в котором можно выбрать необходимый СОМ порт,  гаджетом в который будет выводится сообщения присланные микроконтроллером (по типу терминала) и еще несколькими текстовыми гаджетами для информационных целей.  
 Выбрав нужный порт и подключив тестовую схему к компьютеру через преобразователь, жмем кнопку "Зажечь". При этом в окне приема сообщений появится текст "Led ON", присланный микроконтроллером



В общем все наглядно продемонстрировано на видео




 Отдельное спасибо пользователю с именем Пётр, за помощь в написании программы на PureBasic! Теперь и я помигал светодиодиком!  :D 



Категория: Полезная информация | Добавлено: 26.12.2012
Просмотров: 24239 | Комментарии: 30 | Теги: исходники, PureBasic, микроконтроллер | Рейтинг: 5.0/11
Всего комментариев: 30
0  
30 exersizze   (29.11.2016 18:56)
Михаил, для работы с инфракрасными датчиками и диодами есть команды RC5SEND и GETRC5
http://avrhelp.mcselec.com/index.html?rc5send.htm
http://avrhelp.mcselec.com/index.html?getrc.htm

29 Михаил   (29.11.2016 17:32)
Всем привет.
Подскажите как переменную S передать по инфракрасному каналу как в пультах дистанционного управления.

28 Azbuka   (03.11.2013 23:31)
PureBasic можно изучить за один вечер. Сам изучил по видео этого товарища (http://www.youtube.com/user/toponiks)

+1   Спам
27 Петр   (16.10.2013 10:11)
Для этой задачи, это слишком избыточно.
Можно использовать довольно простой протокол. Например, путь пакет состоит из двух байт: первый - команда, а второй - данные. Если байт "команда" равен 1, то путь это управление светодиодом (данные - информация об вкл/выкл светодиода). Если байт "команда" равен 2, то допустим это управление ШИМ, значение которого находится в байте "Данные".
Ну и так далее.

26 Newmayer   (15.10.2013 13:03)
Что то на подобие ModBus?

25 Петр   (14.10.2013 12:00)
Необходимо разработать протокол обмена между ПК и МК. Обмен данными должен быть в виде пакетов.

24 Newmayer   (13.10.2013 15:11)
Еще раз всем всего доброго!
Как можно организовать прием данных в PureBasic, чтобы принимаемая инфа принималась в разные фреймы?
Например статус светодиода в одном фрейме, а второго в другом...

23 Петр   (06.10.2013 16:05)
Если только один светодиод, то для изменения его яркости достаточно одного байта. Если значение 0, то светодиод необходимо выключить, а если в пределах 1...255, то изменять его яркость.

22 Newmayer   (06.10.2013 05:03)
Это нужно для того, чтобы цифрой 1 зажечь диод, а 100 задать его яркость PWM.
Сделаю отпишусь!

21 Петр   (05.10.2013 11:47)
Нужно передавать не строку, а число?
Тогда в код необходимо добавить такую процедуру, вызывая которую, нужно ей передавать число от 0 до 255.
Чтобы передать два значения, нужно вызвать ее два раза, к примеру,

ComOut_Num(1)
ComOut_Num(100)

; Процедура.

;Процедура передачи данных
Procedure ComOut_Num(Send_data.a)

If IsSerialPort(#COM_Port) ;если порт открыт
WriteSerialPortData(#COM_Port,@send_data,1) ;Шлем данные из переменной Send_data
Else
;Выводим сообщение об ошибке.
MessageRequester("Ошибка","Текущий порт не доступен!",16)
EndIf

EndProcedure

20 Newmayer   (04.10.2013 14:28)
Всем привет! Повторил программу! Работает!
А можно сделать так чтобы она отправляла 2 значения при нажатии на кнопку?
Например 1 , 100.
в контроллере прием Input A , B где А = 1 В = 100

19 sano2000   (22.07.2013 20:20)
2exersizze
Повторил схему, правда без кварца. Это принципиально? Или все-таки можно без кварца. Примеры, которые я видел раньше были без кварца. В общем у меня ничего не работает. Контроллер отсылает данные - это я читаю и все понимаю. Но вот отослать данные на atmega8 (да и на attiny2313, attiny24) - НЕ ПОЛУЧАЕТСЯ. Не хотят они меня видеть :) Подскажите, кто знает, плиз.

P.S. Да, забыл написать. В Proteus-е все работает на ура. Контроллер отзывается очень четко и стабильно, а вот в железе :(

18 exersizze   (21.07.2013 16:43)
VB такой же язык программирования, позволяющий писать взрослые программки. С COM портом он тоже вроде умеет работать, надо копать в этом направлении. А секретов никаких нет))

17 sano2000   (21.07.2013 12:52)
Вопрос разработчику. Принципиально ли использовать PureBasic или можно например написать управление на Visual Basic? Почему спрашиваю, нигде не видел управление мк через VB. Только C, ASM и PureBasic. Данные я с мк получаю прекрасно, а вот отправить команду на мк никак не получается, не видит он их. В Proteus все работает на ура. В Bascom все работает. Как только дело доходит до железа - все сразу перестает откликаться. Может я какой секрет не знаю?

2exersizze Спасибо!

16 skopik   (20.02.2013 23:23)
мне также интересно у меня устройство должно настраиваться по уарт, и дание меньше 4 символов, например set, те же min, lcd идут, даже если набирать их на клаве динамически, тоесть по одному, а больне 3 (start,hour,data,info) никак, может дело в буфере МК, такое может бить ? Для меня ето не критично на изучить би б не плохо.

15 exersizze   (19.02.2013 23:39)
Я упустил один момент, нужно в строке Dim S As String * 1 заменить цифру на количество предполагаемых символов, которые нужно будет принимать. Хотя почему min идет а hour нет это не объясняет..

14 skopik   (19.02.2013 23:06)
У меня почемуто идут только три символа, например min, а hour уже нет

13 exersizze   (19.02.2013 09:27)
Программа будет таже самая, в подпрограмме Getline уже организовано склеивание слов из отдельных символов. Т.е. если отправить в мк любое слово, оно запишется в переменную S

12 skopik   (19.02.2013 00:18)
Здраствуйте, подскажите код МК для приема нескольких символов, те слова, наперед спасибо

+1   Спам
11 k41   (22.01.2013 15:43)
Здравствуйте я тоже загорелся научиться соединять комп с устройствами и буду изучать ваши проекты спасибо что делитесь знаниями

10 XLAM   (02.01.2013 21:18)
Петр, +100500 тебе. Просто заменил строку на WriteSerialPortData(#COM_Port, @send_data, 1) и все проблемы исчезли.

9 Петр   (02.01.2013 15:04)
XLAM, замените проблемную строку на эту WriteSerialPortData(#COM_Port, @send_data, 1)
И проблема исчезнет.

Что касается ошибки на скрине, то это линкер не может найти некоторые функции из библиотеки MVCOM, из которой функция ComWrite().

8 max   (30.12.2012 20:44)
>XLAM
>--UPDATE:
> Первую проблему решил, скачал недостоющую либу.
Интересно, что за либа? У меня вроде все стоят, а компилить не хочет.
>XLAM
> Проблема №2:
http://i54.fastpic.ru/big....4bf.jpg
Это ошибка компилятора. На моей практике такое встречалось, если была запущена прога и я пытался создать приложение.

7 max   (30.12.2012 20:24)
String - это стока. "* 1" - кол-во символов в строке. В данном случае: "Dim S As String * 1" - строка S длинною в один символ. Как-то так. А ввобще в хелпе есть полное описание.

6 implex   (30.12.2012 16:30)
До сих пор не знаю что означает "* 1" в строке "Dim S As String * 1" ?
)))))

5 exersizze   (30.12.2012 13:29)
Может компилятор чудит, у меня версия 4.51(х86)

4 XLAM   (30.12.2012 01:51)
Возникла проблема в строке 40:
ComWrite(SerialPortID(#COM_Port),@send_data,1) ;Шлем данные из переменной Send_data
Не знает что такое ComWrite()

--UPDATE:
Первую проблему решил, скачал недостоющую либу.
Проблема №2:
http://i54.fastpic.ru/big....4bf.jpg

+3   Спам
3 Aleks8383   (27.12.2012 19:08)
Виктор рад что у тебя всё поучилось.Главное это начать изучать(про желание неговорю),а дальше всё пойдёт.Сам неделю наверное читал примеры и книжки по Пурику ,пока недошло осмысление того что написано,а там всё становится всё на свои места.А как страшно и непонятно было :)Главное желание и практика и вё получится.

2 Valera18   (27.12.2012 14:30)
Интересно рассуждает RD3AVJ

Дальше идут Мои мысли:
Кнопки - кнопками, а автономность всё-же лучше:
Зашёл на кухню, один раз хлопнул - свет включился, или два раза хлопнул - свет выключился. Один раз щёлкнул пальцами - чайник включился.

Но на будущее лучше "автономное голосовое управление" на одном микроконтроллере:
Зашёл на кухню - включился свет, "система" сказала тебе "привет". Сказал "включить чайник" чайник включился. Уходя сказал "выключить свет" - свет выключился и "система" сказала тебе "всего хорошего". Ну итак далее у кого сколько идей.

Я немного отошёл от темы :)
Управление микроконтроллером с помощью ПК это хорошая способность (есть плюсы), но недостаток: "энергозатратно".

+1   Спам
1 RD3AVJ   (27.12.2012 12:31)
Все. Приехали. Осталось добавить кнопки "Вскипятить чайник на кухне", "зажечь свет в прихожей" и "Смыть!", привязаться к управлению по удаленке - и умный дом готов)))
Спасибо за статью! Будем изучать!

Добавлять комментарии могут только зарегистрированные пользователи.
[ Регистрация | Вход ]






   EasyEDA:  бесплатный редактор схем

   ✓ Создание схем
   ✓ Возможность симуляции
   ✓ Быстрое создание печатных плат
   ✓ Интуитивно понятный интерфейс

   Нарисуй свою схему прямо сейчас!
   Изготовление печатных плат   https://easyeda.com/order
авторизация
Логин:
Пароль:
Комментарии
Когда не хватает ног. Часть 2. Сдвиговый регистр 74HC595
08.12.2016 - exersizze:
yorx выдалось немного свободного времени, проверил в симуляторе. Проблема...
Логгер температуры 2.0
05.12.2016 - Evgeny6873:
Хотел повторить схему и долго ждал дисплей, два раза заказывал с Китая, пришел. ...
Когда не хватает ног. Часть 2. Сдвиговый регистр 74HC595
01.12.2016 - yorx:
Доброго времени суток, exersizze попробовал Ваш код все равно не работает как на...
Помни об усадке!
30.11.2016 - pchela5:
Автомобильные никакие не лезут?
Помни об усадке!
29.11.2016 - AlekS:
Виктор, спасибо.
С заменой транса в зиму, перестройка не комельфо) Валяет...
Управляем микроконтроллером с ПК по UART
29.11.2016 - exersizze:
Михаил, для работы с инфракрасными датчиками и диодами есть команды RC5SE...
Управляем микроконтроллером с ПК по UART
29.11.2016 - Михаил:
Всем привет.
Подскажите как переменную S передать по инфракрасному каналу...
Помни об усадке!
29.11.2016 - pchela5:
> Если ленту светодиодную порезать и соединить последовательно
Только ...
Когда не хватает ног. Часть 2. Сдвиговый регистр 74HC595
29.11.2016 - exersizze:
yorx, вывод Q7 ' первой микросхемы соединен с DS второй микросхемы? С...


Лучшие цены на 3D принтеры
успей сделать себе подарок к Новому Году! ;)


Prusa i3

Prusa i3 от 12500 р.



Rostoсk

Rostock от 15000 р.