Администрация форума не несёт ответственности за достоверность информации и оставляет за собой право редактировать или в особых случаях даже удалять посты без предупреждения. Спасибо за понимание.

Программирование ATMEL в BASCOM.

Информация о пользователе

Привет, Гость! Войдите или зарегистрируйтесь.


Вы здесь » Программирование ATMEL в BASCOM. » Вопросы - ответы » Goto не уходит в свою метку


Goto не уходит в свою метку

Сообщений 1 страница 29 из 29

1

Всем доброго дня.
Столкнулся с  тем, что в коде по команде Goto программа не переходит в указанную метку.

Алгоритм такой:
1) Кнопками «вверх», «вниз» стрелку  “<=”  устанавливаем к тому,  что хотим изменить(значение времени, таймера и температуры)
2)Нажимаем  кнопку «Выбор»  и попадаем в меню изменения значений выбранного. Если выбрали дату, то указатель(стрелка внизу указывает на то, что мы вводим в данное время) показывает на часы. Изменяем  кнопкой «вверх» часы , далее «Выбор»  . При этом указатель переходит на минуты. И так по всем параметрам.
Сначала все работала нормально. Потом через раз начал не выбираться изменения температуры, потом таймера,  а сейчас можно только значение часов.  Если даже не нажаты никакие кнопки , то программа сразу уходит на установку часов.
Решение искал в замене Goto  на Gosub.     Потому, что думаю дело в стеке.  Даже после Return программа не возвращается, откуда была вызвана подпрограмма.

Код:
$regfile = "m8def.dat"
$crystal = 8000000
$hwstack = 32
$swstack = 8
$framesize = 64
Config Debounce = 50

Config Sda = Portc.1
Config Scl = Portc.0
Config Portd.5 = Output
Config Portb.0 = Output
D3310dc Alias Portb.0
Config Portb.1 = Output
D3310ce Alias Portb.1
Config Spi = Soft , Din = None , Dout = Portd.7 , Ss = None , Clock = Portd.6
' din  - portb.4, scl - portb.3 , dc - portb.5, ce -  portc.0 , reset - vcc
Const Ds1307w = &HD0                                        ' Для Ds1307
Const Ds1307r = &HD1
Declare Sub Get_time()
Declare Sub Pokaz()
Declare Sub Izmer()
Declare Sub Knopki()
Dim Flag_timer As Bit
Dim Zaderzhka As Byte
Dim Temper As Byte , Nagatie As Byte
Dim Chas_t As Byte , Min_t As Byte
Dim Hour As Byte , Seco As Byte , Mine As Byte
Dim Seco_s As String * 2 , Mine_s As String * 2 , Hour_s As String * 2
Dim Chas_ts As String * 2 , Min_ts As String * 2
Dim Temper_s As String * 3
Spiinit
$include "3310init.bas"
Call D3310init
Config Pind.2 = Input : Pind.2 = 1
Config Pind.3 = Input : Pind.3 = 1
Config Pind.4 = Input : Pind.4 = 1
Vverh Alias Pind.2
Vniz Alias Pind.3
Vibor Alias Pind.4
Zaderzhka = 200
'-----------------Выодим на экран значки ---------------------------------------
Restore Banya
Call D3310bmpout
'-------------------------------------------------------------------------------
Telo:
Do
Call Get_time()
Call Pokaz()
Call Izmer()
Call Knopki()
Loop

'-------------------------------------------------------------------------------
Sub Knopki()
If Vverh = 0 Then                                           'Увеличиваем При Нажатии вверх
  Decr Nagatie
  Waitms Zaderzhka
  If Nagatie > 2 Then Nagatie = 0                           '
End If
If Vniz = 0 Then
  Incr Nagatie
  Waitms Zaderzhka
  If Nagatie < 1 Then Nagatie = 0
End If
If Nagatie = 0 Then                                         'Если  Nagatie=0, то стрелка  "<=" указывает на часы
Call D3310position(12 , 0)
Call D3310print( "<=" )
Call D3310position(12 , 2)
Call D3310print( "  " )
Call D3310position(12 , 4)
Call D3310print( "  " )
End If
If Nagatie = 1 Then                                         'Если  Nagatie=1, то стрелка "<=" указывает на таймер
Call D3310position(12 , 0)
Call D3310print( "  " )
Call D3310position(12 , 2)
Call D3310print( "<=" )
Call D3310position(12 , 4)
Call D3310print( "  " )
End If

If Nagatie = 2 Then                                         'Если  Nagatie=2, то стрелка "<="  указывает на температуру
Call D3310position(12 , 0)
Call D3310print( "  " )
Call D3310position(12 , 2)
Call D3310print( "  " )
Call D3310position(12 , 4)
Call D3310print( "<=" )
End If
Select Case Nagatie                                         'В зависимости от значения Nagatie уходим на соответствующую метку
Case 0 : Goto Vvod_vremya                                   'Метка установки  часов
Case 1 : Goto Vvod_timer                                    'Метка установки таймера
Case 2 : Goto Vvod_temp                                     'Метка установки  температуры
End Select
End Sub

'-------------------Установка значения часов в часах ---------------------------
Vvod_vremya:
Do
Waitms Zaderzhka                                            'задержка чтобы значение часов не менялись слишком быстро при установке
Call Get_time()
Call Pokaz()
Call D3310position(3 , 1)                                   ' убираем указатель на часы
Call D3310print( "^" )
If Hour > 23 Then Hour = 0
If Vverh = 0 Then Incr Hour                                 'При нажатии увеличиваем значение часов
Hour = Makebcd(hour)
I2cstart                                                    'записываем значение часов в DS1307
I2cwbyte &HD0
I2cwbyte 2
I2cwbyte Hour
I2cstop
Debounce Vibor , 0 , Vvod_min                               'если нажали на выбор, то уходим на метку Vvod_min
Loop

'-------------------Установка значения минут в часах ---------------------------
Vvod_min:
Do
Waitms Zaderzhka
Call Get_time()
Call Pokaz()
Call D3310position(3 , 1)                                   ' убираем указатель на часы
Call D3310print( "  " )
Call D3310position(6 , 1)                                   ' рисуем указатель на минуты
Call D3310print( "^" )
If Mine > 59 Then Mine = 0
If Vverh = 0 Then Incr Mine
Mine = Makebcd(mine)
I2cstart
I2cwbyte &HD0
I2cwbyte 1
I2cwbyte Mine
I2cstop
If Vibor = 0 Then
  Call D3310position(6 , 1)                                 ' убираем указатель на минуты
  Call D3310print( "  " )
  Waitms Zaderzhka
  Goto Telo
End If
Loop

'------------------------Ввод значения часов таймера --------------------------------------
Vvod_timer:
Chas_t = Hour                                               'берем текущие значения
Min_t = Mine
Do
Waitms Zaderzhka
Call Get_time()
Call Pokaz()
Chas_ts = Str(chas_t)                                       'меняем тип переменных для вывода на экран
Min_ts = Str(min_t)
Chas_ts = Format(chas_ts , "00")                            'Приводим В Удобочитаемую Форму
Min_ts = Format(min_ts , "00")
Call D3310position(3 , 2)
Call D3310print(chas_ts)
Call D3310position(5 , 2)
Call D3310print( ":")
Call D3310position(6 , 2)
Call D3310print(min_ts)
Call D3310position(3 , 3)                                   'указатель рисуем внизу часов
Call D3310print( "^" )
If Chas_t > 23 Then Chas_t = 0
If Vverh = 0 Then Incr Chas_t
If Vibor = 0 Then                                           'При нажатии на выбор убираем указатель внизу на часы и уходим на установку минут
Call D3310position(3 , 3)
Call D3310print( "  " )
Waitms Zaderzhka
Goto Vvod_timer_min
End If
Loop

'------------------------Ввод таймера минуты------------------------------------
Vvod_timer_min:
Do
Call Get_time()
Call Pokaz()
Waitms Zaderzhka
Min_ts = Str(min_t)
Min_ts = Format(min_ts , "00")
Call D3310position(6 , 2)
Call D3310print(min_ts)
Call D3310position(6 , 3)                                   'указатель рисуем внизу минут
Call D3310print( "^" )
If Min_t > 59 Then Min_t = 0
If Vverh = 0 Then Incr Min_t

If Vibor = 0 Then                                           'При нажатии на выбор убираем указатель внизу на минуты и уходим на подтверждение установки таймера
Call D3310position(6 , 3)
Call D3310print( "  " )
Waitms Zaderzhka
Goto Podtverdit
End If
Loop
Return
'------------------------Включение и отключение таймера-------------------------
Podtverdit:
Call D3310position(9 , 2)                                   'Сразу пишем ОК и флаг таймера устанавливаем на 1
Call D3310print( "OK" )
Flag_timer = 1

Do
Waitms Zaderzhka
Call D3310position(9 , 3)                                   'указатель рисуем внизу ОК
Call D3310print( "^" )
If Vverh = 0 Then                                           'Если нажимаем вверх, то устанвливаем таймер
  Call D3310position(9 , 2)
  Call D3310print( "OK" )
  Flag_timer = 1
End If
If Vniz = 0 Then                                            'Если нажимаем вниз, то не устанвливаем таймер и флаг таймера устанавливаем на 0
  Call D3310position(9 , 2)
  Call D3310print( "  " )
  Flag_timer = 0
End If
If Vibor = 0 Then                                           'Если нажимаем выбор, то убираем указатель на подтверждение, запис "ОК" и уходим в метку Telo
  Call D3310position(9 , 2)
  Call D3310print( "  " )
  Call D3310position(9 , 3)
  Call D3310print( " " )
  Waitms Zaderzhka
  Goto Telo
End If
Loop
'----------------------Ввод температуры-----------------------------------------
Vvod_temp:
Do
Waitms Zaderzhka
Temper_s = Str(temper)
Temper_s = Format(temper_s , "000")
Call D3310position(3 , 4)
Call D3310print(temper_s)
Call D3310position(3 , 5)
Call D3310print( "^" )
If Temper > 125 Then Temper = 20
If Vverh = 0 Then Temper = Temper + 5

If Vibor = 0 Then
Call D3310position(3 , 5)
Call D3310print( " ")
Waitms Zaderzhka
Goto Telo
End If
Loop
'-----------------Часы---------------------------------------------------------
Sub Get_time()
I2cstart                                                    ' Generate start code
I2cwbyte Ds1307w                                            ' send address
I2cwbyte 0                                                  ' start address in 1307
I2cstart                                                    ' Generate start code
I2cwbyte Ds1307r
I2crbyte Seco , Ack
I2crbyte Mine , Ack
I2crbyte Hour , Nack
I2cstop
Seco = Makedec(seco)
Mine = Makedec(mine)
Hour = Makedec(hour)
Seco_s = Str(seco)    'Для вывода на экран меняем тип переменных на string
Mine_s = Str(mine)
Hour_s = Str(hour)
If Seco < 10 Then Seco_s = Format(seco_s , "00")            'Приводим в удобочитаемую форму
If Mine < 10 Then Mine_s = Format(mine_s , "00")
If Hour < 10 Then Hour_s = Format(hour_s , "00")
End Sub
'-----------------Показываем часы на экране-------------------------------------
Sub Pokaz()
Call D3310position(3 , 0)
Call D3310print(hour_s)
Call D3310position(5 , 0)
Call D3310print( ":")
Call D3310position(6 , 0)
Call D3310print(mine_s)
Call D3310position(8 , 0)
Call D3310print( ":")
Call D3310position(9 , 0)
Call D3310print(seco_s)
End Sub
'-----------------Измерение температуры-----------------------------------------
Sub Izmer()
'Тут еще код не дописан
End Sub

'-------------------------------------------------------------------------------
$include "3310end.bas"
$include "Fon.bas"


http://s3.uploads.ru/t/gFYdT.jpg

0

2

Если я правильно прочитал вашу программу - она работает в RealTime.

В этом случае вполне реально поймать подобный глюк, особенно при наличии каких-либо временных переменных, используемых в разных местах.

Лучший вариант - обработка кнопок по прерыванию.

0

3

Неудивительно что программа не работает. Переход в произвольную область по Goto из подпрограммы/процедуры/функции запрещены (точнее нужно понимать что даешь и как обойти грабли связанные по стеком). Это нужно запомнить, иначе стабильной работы не стоит ожидать.
Программу нужно стараться писать так чтобы в ней не было ни одного Goto.

0

4

Nord написал(а):

Лучший вариант - обработка кнопок по прерыванию.

Да, правильно прочитали.
Не хотелось бы использовать прерывания. Программа и без прерываний успевает откликнуться на нажатие.

Отредактировано Niya (2017-10-08 21:00:25)

0

5

Пётр написал(а):

Программу нужно стараться писать так чтобы в ней не было ни одного Goto.

Тогда придется всю программу переписать.
В хелпе прочитал про $hwstack,$swstack,$framesize . У меня с таким количеством Call $hwstack задан,по-моему, маловато. Попробую задать значения корректно.

0

6

Niya написал(а):

Тогда придется всю программу переписать

Вот этот участок все косяки собирает:
Select Case Nagatie                                         'В зависимости от значения Nagatie уходим на соответствующую метку
Case 0 : Goto Vvod_vremya                                   'Метка установки  часов
Case 1 : Goto Vvod_timer                                    'Метка установки таймера
Case 2 : Goto Vvod_temp                     

Можно уменьшить мучения, перенеся Knopki в главный цикл.
Наполняемость стека уменьшится

И оптимизировать обращение к дисплею.
При обращении к дисплею используются одинаковые значения, кроме одного.
Выделить этот пакет в отдельную Sub, задавая при обращении нужные значения.

0

7

Пётр написал(а):

Программу нужно стараться писать так чтобы в ней не было ни одного Goto.

Или нужные Goto ограничивать в рамках одной Sub. ;)

+1

8

Применение LCD Nokia 3310_5110

Применение Ds1307

Отредактировано sasha_1973 (2017-10-09 04:55:56)

0

9

Пётр написал(а):

Переход в произвольную область по Goto из подпрограммы/процедуры/функции запрещены


Не согласен, Goto - крайне полезная функция

Пётр написал(а):

точнее нужно понимать что даешь и как обойти грабли связанные по стеком


Полностью согласен.

0

10

sasha_1973 написал(а):

Не согласен, Goto - крайне полезная функция

Плюсуюсь, только, ИМХО, Петр не запрещает ее использование... ;)
Просто последнее время (не раз читал) использование Goto почему-то считается "чайниковством"... ;)

Переход в произвольную область по Goto из подпрограммы/процедуры/функции запрещены

Скорее, речь идет о правилах переходов.
Если выйти из Sub "нестандартным" образом (посредством Goto), то неизбежно появится мусор в стеке, что на каком-то этапе так же неизбежно вызовет сбой.

Если же после "правильного" выхода по результатам работы Sub начать "ветвиться" силами Goto, то ничего страшного не произойдет, т.к. стек отработан правильно.

Отредактировано Nord (2017-10-09 05:53:00)

0

11

Nord написал(а):

Просто последнее время (не раз читал) использование Goto почему-то считается "чайниковством"...


Наверное потому, что неправильно используют.

Повторюсь, Goto; JMP; IJMP; EIJMP  -  в высшей степени полезные функции, но, как и везде, есть свои ограничения.

Пример подтверждающий полезность инструкции, явное ускорение + экономия памяти

Nord написал(а):

Петр не запрещает ее использование...

Просто неправильно выразился.

+1

12

sasha_1973 написал(а):

Повторюсь, Goto; JMP; IJMP; EIJMP  -  в высшей степени полезные функции, но, как и везде, есть свои ограничения.

А я и не возражаю насчет полезности, сам использую постоянно. ;)

0

13

Nord написал(а):

Можно уменьшить мучения, перенеся Knopki в главный цикл.
Наполняемость стека уменьшится
И оптимизировать обращение к дисплею.
При обращении к дисплею используются одинаковые значения, кроме одного.
Выделить этот пакет в отдельную Sub, задавая при обращении нужные значения.

Спасибо за подсказку.Попробую пойти этим путем.

0

14

sasha_1973 написал(а):

Наверное потому, что неправильно используют.

А как правильно им пользоваться? Точнее, где прочитать про это? Я , как понимаю, отличие Goto от Сall и Gosub в том, что при вызове подпрограммы с помощью  Сall и Gosub в стек записывается адрес, откуда была вызвана подпрограмма, чтобы благополучно  туда вернуться. А при использовании Goto не записывается, а просто осуществляется переход на метку. Я правильно понимаю? Так почему же, если ничего не записывается в стек, Goto вводит такую чихарду в стек?

0

15

Niya написал(а):

Так почему же, если ничего не записывается в стек, Goto вводит такую чихарду в стек?

Потому что при переходе в подпрограмму или функцию в стек записывается адрес (а при наличии локальных переменных, которыми являются также аргументы, под них резервируется память), и при возврате из подпрограммы или функции необходимо все вернуть до того состояния что было перед вызовом. При переходе по Goto за пределы подпрограммы или функции этого не происходит.

+3

16

Пётр написал(а):

Потому что при переходе в подпрограмму или функцию в стек записывается адрес (а при наличии локальных переменных, которыми являются также аргументы, под них резервируется память), и при возврате из подпрограммы или функции необходимо все вернуть до того состояния что было перед вызовом. При переходе по Goto за пределы подпрограммы или функции этого не происходит.

10 баллов из 5-ти возможных

0

17

Niya написал(а):

Я , как понимаю, отличие Goto от Сall и Gosub в том, что при вызове подпрограммы с помощью  Сall и Gosub в стек записывается адрес, откуда была вызвана подпрограмма, чтобы благополучно  туда вернуться. А при использовании Goto не записывается, а просто осуществляется переход на метку. Я правильно понимаю?


Нечего возразить!

Niya написал(а):

Так почему же, если ничего не записывается в стек, Goto вводит такую чихарду в стек?


Потому, что Вы переходите по Goto не сохраняя адрес возврата из текущей Sub по Return или End Sub.

0

18

Niya написал(а):

Так почему же, если ничего не записывается в стек, Goto вводит такую чихарду в стек?

Про вызов и возврат из подпрограмм все правильно поняли, но вот при чем тут Goto ?
Это - оператор перехода, он при выполнении стеком не пользуется.

В данной ситуации, если выход из п/пр был выполнен некорректно, первый же встретившийся Return или End Sub вытащит из стека ближайший адрес и вернется в неизвестность...

Стек используется не только п/пр.
Это - только видимая нам часть того айсберга.
Эти значения для чего:
$hwstack = 32
$swstack = 8
Насчитайте в своей программе хотя бы шесть "углублений" в п/пр одновременно... ;)
Вызов п/пр2 из п/пр1, из п/пр2 - в п/пр3 ... и так далее с последовательным возвратом.

И выход по Goto на любой такой "глубине" влечет неиспользование ячейки стека, которая автоматически становится его "дном".
Рано или поздно это "дно" достигнет "краев" и тогда - здравствуй глюк ! ;)

Как вариант - чистить стек, но это уже будет совсем "дурной тон", да и как это правильно делается я не помню... ;)

0

19

Пётр написал(а):

Потому что при переходе в подпрограмму или функцию в стек записывается адрес (а при наличии локальных переменных, которыми являются также аргументы, под них резервируется память), и при возврате из подпрограммы или функции необходимо все вернуть до того состояния что было перед вызовом. При переходе по Goto за пределы подпрограммы или функции этого не происходит.

Айа-йай...Я кажется уже догоняю ) Это получается : я оставил вещи на вокзале и сказал , что скоро вернусь за ними. Goto посадил меня на поезд и отправил куда подальше, а вещи остались там.  Со временем получается, что таких бесхозных вещей так много(благодаря Goto), что они мешают всем...

+2

20

Красивее и не скажешь !

0

21

Nord написал(а):

Насчитайте в своей программе хотя бы шесть "углублений" в п/пр одновременно...
Вызов п/пр2 из п/пр1, из п/пр2 - в п/пр3 ... и так далее с последовательным возвратом.
И выход по Goto на любой такой "глубине" влечет неиспользование ячейки стека, которая автоматически становится его "дном".
Рано или поздно это "дно" достигнет "краев" и тогда - здравствуй глюк !

По-моему, это и есть "неправильное" использование Goto. И , как я понял, если вызвали подпрограмму, то желательно End Sub или Return-ом сразу же возвратиться. Чтобы они корректно нашли то, что записалось в стек до вызова.
С учетом замечаний, советов форумчан начал переписывать код. Допишу, проверю на железе. Если что -напишу. Спасибо всем.

Отредактировано Niya (2017-10-09 15:12:04)

0

22

Niya написал(а):

Со временем получается, что таких бесхозных вещей так много (благодаря Goto), что они мешают всем...

Абсолютно верно.
Для пущего понимания поясню работу стека...

Имеем четыре подпрограммы - П1, П2, П3 и П4.
Присвоим каждой из них цвет:
П1 - синий
П2 - зеленый
П3 - желтый
П4 - красный
И "выдадим" им каждой в неограниченном количестве диски соответствующего цвета.

Имеем (объявляем) стек объемом (глубиной) восемь адресов.
Представим стек в виде стакана.

Теперь работа...
Вариант 1.
В теле основной программы происходит вызов П1.
В стакан кладем синий диск (адрес возврата).
По окончании выполнения П1 диск из стакана забираем.
Стакан (стек) пуст...

Вариант 2.
Вызываем П1 (синий в стакан).
Из П1 вызываем П4 (красный в стакан поверх синего).
Из П4 вызываем П2 (зеленый в стакан).
Теперь синий мы сможем достать только в одном случае - достав зеленый и красный...
Завершаем П2 (Return или End Sub) - достаем зеленый.
Завершаем П4 - достаем красный.
Завершаем П1 - достаем синий...
Стакан пуст.

Вариант 3.
Вызвали П1 (синий в стакан).
Из П1 вызвали П3 - желтый в стакан сверху синего, т.к. П1 еще не завершена.
И тут "бац" - выход из П3 силами Goto...
В стакане остались и синий и желтый, которые уже выковыривать никто не будет, т.к. они никому уже не нужны...
А свободное место в стеке уменьшилось...

+4

23

100 баллов из 5-ти возможных

0

24

sasha_1973 написал(а):

100 баллов из 5-ти возможных

:blush:

0

25

Всем доброго дня! Заработала все таки она у меня  8-)  http://s1.uploads.ru/t/qhWdP.jpg
Чтобы обойтись без моего любимого Goto в код пришлось ввести кучу переменных bit(в качестве флагов), но ,главное, программа работает стабильно.  В самом интересном  месте Mega8 что-то заглючил, не хочет заливаться прошивка.Главное сам МК работает, но на запросы USB ASP не отвечает :disappointed: Прозванивал от ножек МК до программатора-  все в норме. Ну да ладно...Придется ждать заказ или перенести на 328-ую..Вопрос такой:кто-нибудь применял  терморезисторы в качестве датчиков? Лучше работать(для МК) с b-уравнением или  таблицами  данных? В b-уравнении вычисляется логарифм  и придется применять переменные типа Single. Думаю, что после этого нагрузка будет приличная на МК и поймать кнопки без прерываний не смогу..

Отредактировано Niya (2017-10-16 18:47:54)

0

26

Niya написал(а):

в код пришлось ввести кучу переменных bit(в качестве флагов)

Можно не сотворять кучу переменных Bit, а использовать побитное обращение к переменной.

Например, вместо восьми битовых a, b, c... можно объявить одну Byte:
Dim Flags As Byte
Для памяти расписываем значения флаговых битов:
' 0 - флаг такой-то
' 1 - флаг такой-то
...
' 7 - флаг такой-то

При этом нигде уже не объявлять переменную с этим именем !

Работа с ней:
Flags.0 = ... - записываем в 0 бит нужный флаг

If Flags.3 = ... - проверяем 3 бит

ИМХО, так удобнее и памяти меньше занимает хоть на чуть-чуть...
В памяти резервируется место не только под саму переменную, но и под ее идентификатор.
В случае использования восьми штук битовых - 16 "мест", а в случае одной байтовой - 7...

Upd

а в случае одной байтовой - 7...

Биг сорри - не 7, а 3 или 4 (в зависимости от объема используемой памяти)...
Очепятка ! ;)
Отвечал, будучи на работе и мысли вынужденно раздваивались... ;)

Отредактировано Nord (2017-10-17 19:33:42)

+2

27

А у меня никогда проблем небыло с Goto и Gosub, даже странно как-то. судя по коду как-то не прилично из Sub и подпрограмм переходить на GOTO, предполагаю контроллер хранить путь обратно.

0

28

Ev3658 написал(а):

судя по коду как-то не прилично из Sub и подпрограмм переходить на GOTO

это "неприличие" товарищи указали, разжевали...сейчас код переделан, работает нормально

0

29

Niya написал(а):

такой:кто-нибудь применял  терморезисторы

Применял. Конечно, лучше состряпать таблицу в excel и там все посчитать, для мк останется лишь взять нужное значение (полученное значение adc = строка таблицы)

0


Вы здесь » Программирование ATMEL в BASCOM. » Вопросы - ответы » Goto не уходит в свою метку