Автор: WildCat
Подпрограммы и функции используются, когда у вас есть несколько одинаковых фрагментов кода в различных частях программы. Допустим, у вас есть такая программа:
Dim ADCval as byte Dim ADCchannel as byte Const ADCreadaddress = &H66 'Read first ADC channel ADCchannel=0 I2cstart I2cwbyte ADCreadaddress I2cwbyte ADCchannel I2crbyte ADCval Print "ADC voltage on channel: " ; ADCchannel; " is: " ; ADCval 'Read second ADC channel ADCchannel=1 I2cstart I2cwbyte ADCreadaddress I2cwbyte ADCchannel I2crbyte ADCval Print "ADC voltage on channel: " ; ADCchannel; " is: " ; ADCvalЕё можно записать так:
Dim ADCval as byte Dim ADCchannel as byte Const ADCreadaddress = &H66 Declare Sub ADCread(byval ADCchannel as byte, ADCval as byte) 'Read first ADC channel ADCchannel=0 Call ADCread(AdDCchannel, ADCval) Print "ADC voltage on channel: " ; ADCchannel; " is: " ; ADCval 'Read second ADC channel ADCchannel=1 Call ADCread(AdDCchannel, ADCval) Print "ADC voltage on channel: " ; ADCchannel; " is: " ; ADCval Sub ADCread(byval ADCchannel as byte, ADCval as byte) I2cstart I2cwbyte ADCreadaddress I2cwbyte ADCchannel I2crbyte ADCval End SubВо втором случае, подпрограмма - единственное место, где считывается значение АЦП. В основной программе дважды происходит вызов подпрограммы - для считывания значений 0 и 1 каналов АЦП.
Преимущество подпрограммы в том, что повторяющиеся участки кода используются в тексте программы только один раз. Если вдруг потребуется изменить код, это придётся сделать лишь один раз. Когда используется много повторяющихся фрагментов, вам придется изменять каждый из них. Однажды вы таки забудете исправить один из фрагментов и будете очень долго искать проблему.
Подпрограмма вызывается таким образом:
Call ADCread(ADCchannel, ADCval)
Подпограмма имеет название и может иметь дополнительные параметры. В данном случае это ADCchannel и ADCval. подпограмма использует параметр ADCchannel, чтобы считать значение с нужного канала. Считанное значение помещается в ADCval и возвращается подпрограммой по достижении её конца - End Sub. Поэтому параметры могут работать в обоих направлениях - от основной программы к подпрограмме и наоборот.
Можно указать подпрограмме, что данные ей параметры нужно оставить неизмененными. Для этого при объявлении используется команда Byval. Тогда BASCOM создаст в памяти копию этой переменной и будет работать с ней. Исходная переменная останется нетронутой, что бы не происходило с ней в подпрограмме. В вышеописанном примере с переменной ADCchannel не происходят изменения в подпрограмме, так как она специально описана в объявлении подпрограммы.
Обратный параметр - Byref - устанавливается по умолчанию. Его можно не указывать. В том случае все изменения, которые подпрограмма делает с переменной, останутся после её работы.
Как вы уже поняли, подпограммы, как и переменные, должны быть объявлены в программе заранее:
Declare Sub ADCread(byval ADCchannel, as byte, ADCval as byte)
Вот еще замечательный пример использования подпрограмм. Подключите ЖКИ к AT90S2313 по стандартной схеме компилятора и наблюдайте за работой программы (или можете сделать это в симуляторе).
$regfile = "2313def.dat" $crystal = 4000000 Const Barmaxchar = 16 Dim Forcounter As Byte Dim Logval As Byte Declare Sub Bar(logvalue As Byte) Deflcdchar 0 , 14 , 10 , 14 , 21 , 14 , 10 , 17 , 17 'jumping man-a Deflcdchar 1 , 14 , 10 , 21 , 21 , 14 , 10 , 10 , 17 'jumping man-b Deflcdchar 2 , 32 , 32 , 32 , 32 , 32 , 32 , 32 , 32 'empty box Deflcdchar 3 , 16 , 16 , 16 , 16 , 16 , 16 , 16 , 0 '1/5 box Deflcdchar 4 , 24 , 24 , 24 , 24 , 24 , 24 , 24 , 0 '2/5 box Deflcdchar 5 , 28 , 28 , 28 , 28 , 28 , 28 , 28 , 0 '3/5 box Deflcdchar 6 , 30 , 30 , 30 , 30 , 30 , 30 , 30 , 0 '4/5 box Deflcdchar 7 , 31 , 31 , 31 , 31 , 31 , 31 , 31 , 0 'full box Cls Cursor Off Do 'Generate random numbers to display as bar For Forcounter = 1 To 40 Logval = Rnd(40) Call Bar(logval) Waitms 500 Next Logval 'Count down to create diminishing bar For Logval = 40 To 1 Step -1 Call Bar(logval) Waitms 250 Next Logval Loop End Sub Bar(logvalue As Byte) Local Lognumboxes As Byte Local Logbarremainder As Byte Local Logboxnumber As Byte Locate 1 , 1 Lognumboxes = Logvalue / 5 'calc number of boxes in bar Logbarremainder = 5 * Lognumboxes 'and determine remainder Logbarremainder = Logvalue - Logbarremainder For Logboxnumber = 1 To Lognumboxes 'number of boxes to lcd Lcd Chr(7) Next Logboxnumber Logbarremainder = 2 + Logbarremainder 'make remainder point to Lcd Chr(logbarremainder) 'correct lcd char and output char to lcd Lognumboxes = Lognumboxes + 1 'Fill remainder with spaces For Logboxnumber = Lognumboxes To Barmaxchar Lcd " " Next Logboxnumber End SubВ этом примере основная программа генерирует случайные числа для отображения в виде столбца. Затем она вызывает подпограмму Bar с параметром Logvalue. Подпрограмма, в свою очередь, рассчитывает количество полностью закрашеных символов, затем выбирает заранее описаный символ из 1-4 вертикальных черточек. Наконец, она заполняет оставшееся место на экране пробелами, чтобы убрать следы предыдущих показаний.
Функции
Функции подобны подпрограммам, но они возвращают хотя бы одно значение вызвавшей программе. Например:
Dim DDSWord as Long Const DDSClock = 100000000 '100MHz Declare Function MakeDDSWord(byref Frequency as Long) as Long DDSWord = MakeDDSWord(Frequency) Function MakeDDSWord(byref Frequency as Single) as Long MakeDDSWord = 2 ^ 32 MakeDDSWord = MakeDDSWord / DDSClock MakeDDSWord = MakeDDSWord * Frequency End FunctionВ строке
DDSWord = MakeDDSWord(Frequency)
функция MakeDDSWord вызывается с аргументом Frequency. Функкция должна вернуть хотя бы одно значение, но возможно (хотя и жутко нелогично для функций) изменение аргументов, данных функции. Чтобы разрешить это сделать, используйте параметры Byval и Byref, как и для подпрограмм.Локальные переменные
В подпрограмме или функции можно объявить переменные, существующие только внутри неё. Они недоступны из основной программы. Для объявления такой переменной используйте оператор Local:
Local Temporaryval as Integer
Local Justfornow as Long
Все типы переменных, за исключением Bit, могут быть объявлены как локальные. Переменные типа Bit всегда глобальные.