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

Управляем микроконтроллером с ПК по 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
Просмотров: 41989 | Комментарии: 32 | Теги: исходники, PureBasic, микроконтроллер | Рейтинг: 5.0/11
Всего комментариев: 321 2 »
32 belcof   (23.06.2017 14:10) [Материал]
Привет.
Как настроить фьюзы от внутреннего и внешнего кварца для SinaProg.
Установлено так:
Int. RC Osc. 8 MHz; Start-up time: 14 CK + 65 ms; [CKSEL=0100 SUT=10]; default value
но отказывается мигать на тиньке2313

+1   Спам
31 ven100   (04.01.2017 13:07) [Материал]
Очень понятно и доходчиво всё написано, если бы везде так всё пояснялось было бы неплохо. Спасибо!

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) [Материал]
Виктор рад что у тебя всё поучилось.Главное это начать изучать(про желание неговорю),а дальше всё пойдёт.Сам неделю наверное читал примеры и книжки по Пурику ,пока недошло осмысление того что написано,а там всё становится всё на свои места.А как страшно и непонятно было :)Главное желание и практика и вё получится.

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






авторизация