Только в этом месяце - скидки на паяльники и электронику с нашими кодами (123avr.com) :




Страницы курса:

Уроки

Задания


index.htm
01.htm
02.htm
03.htm
04.htm
05.htm
06.htm
07.htm
08.htm
09.htm


z1.htm
z2.htm
z3.htm
z4.htm
z5.htm
z6.htm
z7.htm
z8.htm
z9.htm
z10.htm
z11.htm

New! - ФОРУМ!

Совет - умейте правильно находить информацию!


Добавить страницу в закладки:

стр. 5 часть 2

Язык Си для МК

часть 2 

 

Объявление  переменных 

Перед использованием переменной в программе на Си  её  необходимо объявить - т.е. указать компилятору какой тип данных она может хранить и как она называется.Наиболее подробно об этом по ссылке: 1.2. ТИПЫ ДАННЫХ И ИХ ОБ ЯВЛЕНИЕ. Ниже сжато - самое главное:

Формат объявления переменной таков:

[<storage modifier>] <type definition> <identifier>;

 

     
 

[<storage modifier>]- необязательный элемент, он нужен только в некоторых случаях и может быть: 

extern - если переменная объявляется во внешнем файле - например в хидере   delay.h  приведенном выше. 
volatile - ставьте если нужно предотвратить возможность повреждения содержимого переменной в прерывании, и не позволить компилятору попытаться выкинуть её при оптимизации кода. 
Советую ставить если не знаете точно нужно или нет !  

пример:
volatile unsigned char x;

static - если переменная локальная т.е. объявлена в какой либо функции и должна сохранять свое значение до следующего вызова этой функции. 

flash и eeprom - используются с указателями. 

 
     

Глобальные переменные объявляются до появления в тексте программы какой либо функции. Глоабльные переменные доступны в любой функции программы. 

Локальные переменные объявляются в самом начале функций  - т.е. сразу после фигурной скобки  "{". Локальные переменные доступны только в той функции где они объявлены!  В разных функциях могут быть объявлены локальные переменные с одинаковыми именами - я не советую вам так делать. Советую не использовать ЛОКАЛЬНЫЕ переменные в главной функции main.

<type definition> - тип данных которые может хранить переменная.

наиболе часто используемые типы данных :

  • unsigned char - хранит числа от 0 до 255 (байт)

  • unsigned int - хранит числа от 0 до 65535 (слово == 2 байта)

  • unsigned long int - хранит от 0 до 4294967295   (двойное слово == 4 байта)

Подробнее все типы данных посмотрите в Help CVAVR\bin\CVAVR.HLP  Раздел "Data Types"  

     
 

Вместо unsigned char - можно писать писать просто  char, так как компилятор по умолчанию считает char  без знаковым байтом. А если вам нужен знаковый байт то объявляйте его так :

signed char  imya_peremennoi;

 
     

 
<identifier> - имя переменной - некоторый набор символов по вашему желанию, но не образующий зарезервированные слова языка Си.

Выше был уже пример идентификатора - имени переменной:  

imya_peremennoi

 


Credit Star


     
 

Желательно давать осмысленные имена переменным и функциям - напоминающие вам об их назначении. 

принято использовать маленькие буквы, а для отличия имен переменных от названия функций - имена переменных можно например начинать с буквы, а названия функций (кроме main конечно) с двух символов подчеркивания. 

Например так :  

  moya_peremennaya        __vasha_funkziya

 
     

Внимание! Глобальные переменные, а также локальные с модификатором static - при старте и рестарте программы равны 0 если вы не присвоили им (например оператором =) иное значение при их объявлении или по ходу программы.Подробные примеры объявления переменных посмотрите пожалуйста в разделе Variables в "Хелп" компилятора.   Вот несколько примеров объявления переменных :

unsigned char my_peremen = 34;
unsigned int big_peremen = 34034;

Это объявлены две переменные и им присвоены значения.

Первая   my_peremen - символьного типа - это 1 байт, она может хранить число от 0 до 255. В данном случае в ней хранится число 34.

Вторая  big_peremen  - целого типа, два байта, в ней может хранится число от 0 до 65535 , а в примере в  неё поместили десятичное число 34034.

Пример массива содержащего  3 числа или элемента массива.

char mas[3]={11,22,33};

Нумерация элементов начинается с  0. Т.е. элементы данного массива называются

mas[0], mas[1], mas[2]

и в них  хранятся десятичные числа 11,  22 и 33.

Где то в программе вы можете написать:

mas[1] = 210;

Теперь  в  mas[1] будет хранится число  210

- массивы могут быть многомерными,
- можно не присваивать значений элементам  массива при объявлении

НО только при объявлении вы можете присвоить значения всем элементам массива сразу ! Потом это можно будет сделать только индивидуально для каждого элемента.

 

Строковая переменная  или массив содержащий строку символов.

char stroka[6]="Hello";

Символов (букв) между кавычками  5 , а я указал размер строки 6  !

Дело в том, что строки символов должны заканчиваться десятичным числом 0.

Не путайте его с символом '0' которому соответствует десятичное число 48 по
таблице ASCII  - которая устанавливает каждому числу определенный символ.

Например :

Элемент строки  stroka[1] содержит число 101  которому по таблице ASCII  соответствует символ 'e'
Элемент stroka[4] содержит число 111  которому соответствует символ 'o'
Элемент   stroka[5] содержит число 0  которому соответствует символ  
'NUL'  его еще обозначают вот так  
'\0'

Строковая переменная может быть "распечатана" или выведена в USART MK вот так:

printf("%s\n", stroka); 

     
 

Вы можете преобразовать строковую переменную в число  ! Если исходная строка символов такая  :

char stroka[]="3654694";

то вот так:

perem_1 = atoi(stroka);

мы поместим в переменную  perem_1   (которую должны были ранее в программе объявить как  "беззнаковую целую") число 36546. 

Это число влезет в переменную perem_1 которая может хранить числа от 0 до 65535.А вот 9 и 4 уже не поместятся.Для бОльших чисел есть функция   -   atol() Чтобы использования эти функции необходимо включить в начале программы заголовочный файл :

#include <stdlib.h>

Для преобразования числа в строку

есть  itoa()  и  ltoa()


Подробнее об этих и других полезных функциях смотрите раздел "Standard Library Functions"  справки компилятора.

 
 

 

 

Советую вам скачать  заголовочный файл m8 128.h  Он содержит названия битов МК ATmega8  -16 -32 -64 -128 и сокращенные названия типов данных как в компиляторе IAR. вот отрывок из  него:

#define u8 unsigned char // 0 to 255
#define s8 signed char // -128 to 127

#define u16 unsigned int // 0 to 65535
#define s16 signed int // -32768 to 32767

#define u32 unsigned long int  // 0 to 4294967295

#define s32 signed long int  // -2147483648 to 2147483647

#define f32 float // ±1.175e-38 to ±3.402e38
#define d32 double // ±1.175e-38 to ±3.402e38


После включения моего  "хидера"  в текст вашей 
программы вы сможете писать вместо длинного

unsigned long int <имя 32 битной переменной>

коротко :  

  • u32 <имя 32 битной переменной>

  •  u - беззнаковая - значит не отрицательная

  •  s - значит переменная со знаком 

  • 32 - количество бит в переменной

Следующий пункт в структуре программы на Си для МК ...

 

     
 

/* п.5  описание функций - обработчиков прерываний Подробно о прерываниях в AVR читайте на стр. 3 курса ! мы будем использовать в   ЭТОЙ программе - только одно прерывание и значит одну функцию обработчик прерывания. Программа будет переходить на неё при возникновении прерывания : 

ADC_INT - по событию "окончание АЦ преобразования"  */

interrupt [ADC_INT] void adc_isr(void)
{ 

PORTB=(unsigned char) ~(ADCW>>2);
/* отобразить горящими светодиодами подключенными от + питания МК через резисторы 560 Ом к ножкам порта_B  старшие 8 бит результата аналого-цифрового преобразования  */

/* сделаем паузу 127 мСек чтобы в реальном устройстве можно было увидеть переключение светодиодов  */
delay_ms(127); 

/* В реальных программах старайтесь не делать пауз в прерываниях! Обработчик прерывания должен быть как можно короче и быстрее   */

 // начать новое АЦ преобразование
ADCSRA|=0x40;

} // закрывающая скобка для обработчика прерывания

 
     

Функция обработчик прерывания может быть названа вами  произвольно - как и любая функция кроме  main
Здесь она названа :        adc_isr 

При каком прерывании ее вызывать - компилятор узнает из строчки : 

interrupt[ADC_INT]  

по первому зарезервированному слову - interrupt - он узнаёт, что речь идет об обработчике прерывания, а номер вектора прерывания (адрес куда физически, внутри МК перескочит программа при возникновении прерывания) будет подставлен вместо ADC_INT препроцессором компилятора перед компиляцией - этот номер указан в подключенном нами ранее заголовочном файле ("хидере") описания "железа" МК - mega16.h - это число сопоставленное слову ADC_INT.

Очень информативна и тем ценна для обучающегося следующая строка программы:

PORTB = (unsigned char) ~(ADCW>>2);

Давайте проанализируем как она работает.

=     оператор присваивания.  Он означает присвоить значение выражения
справа от оператора присваивания той переменной что указана слева от него. 

Значит нужно вычислить выражение справа и поместить 
его в переменную  PORTB.

Вычислим что справа от оператора присваивания.

ADCW - это переменная слово (двухбайтовая величина - так она объявлена в файле mega16.h) в котором CodeVisionAVR сохраняет 10-битный результат АЦП - а именно в битах9_0 (биты с 9-го по 0-й) т.е. результат выровнен обычно - вправо. 

Но у нас, в VMLAB только 8 светодиодов и нужно отобразить 8 старших бит результата - т.е. биты_9_2  - для этого мы сдвигаем все биты слова ADCW  вправо на 2 позиции

ADCW >> 2 /* биты 1 и 0 вылетают вправо из числа в небытие, 
бит_9 перемещается в позицию бит_7, бит_8 в позицию бит_6 и так далее до бит_2 становится бит_0  */

Теперь старшие 8 бит результата АЦП встали в биты7_0
младшего байта  (LowByte - LB) слова ADCW

       
 

>> n

означает сдвинуть все биты числа вправо на n  позиций это равносильно делению на 2 в сепени n

 
 

 

 

 
 

<< n

означает сдвинуть все биты числа влево на n позиций это равносильно умножению на 2 в сепени n

 
       
 

Сдвиг используется очень часто !

 
 

 

 

Светодиоды подключены так как написано выше - т.е.  подключены правильно !

Загораются (показывая "1") при "0" на соответствующем выводе МК - значит нам нужно выводить в PORTB число в котором "1" заменены "0" и наоборот  -  это делает как я рассказал выше :

~           операция побитного инвертирования

Значит результатом этого выражения

 ~(ADCW>>2)

будут инвертированные 8 старших бит результата АЦП находящиеся в младшем (правом - LB) байте двух байтового слова ADCW


Выше я уже говорил что : 
в Си в переменную можно помещать только тот тип данных который она может хранить !

Так как PORTB это байт, а ADCW - это два байта, то прежде чем выполнить оператор присваивания (это знак  = ) нужно преобразовать слово (слово - word - значит два байта)  ADCW  в без знаковый байт.

     
 

Преобразование типов данных - делают так :

перед тем что надо преобразовать записывают в скобках (       ) 
тип данных к которому нужно преобразовать.

 
 

 

 


Пишем ...

(unsigned char) ~(ADCW>>2)

Результат этой строки - один байт и мы можем поместить его в PORTB

Если в регистре DDRB все биты равны "1" - т.е. все ножки порта_B выходы, мы безусловно увидим старшие 8 бит результата АЦП горящими светодиодами.

Вам должна быть абсолютно понятна разобранная строка:

PORTB = (unsigned char) ~(ADCW>>2);

Если это не так то повторите разбор, и почитайте рекомендованное ниже по Си.

разберем еще одну строчку :

ADCSRA|=0x40;

обратите внимание на необходимость ставить в конце выражений точку с запятой - не забывайте ! Эта строка означает следующее:  
Двигаемся слева на право :

  • - берем значение переменной ADCSRA (это регистр МК - значит программа прочитает его, возьмет число из него) 

  • - выполняем с этим числом операцию обозначаемую вертикальной черточкой   |  ( это поразрядная операция ИЛИ - только "0" и "0" дают "0" ) с числом 0x40

  • - присвоим или поместим результат поразрядного ИЛИ обратно в переменную ADCSRA - т.е. запишем результат в регистр ADCSRA  

  • 0x40   это в двоичном виде:  0100 0000 

так как в результате поразрядного  ИЛИ только два "0" дают "0" биты в ADCSRA напротив нулей не изменятся, а вот бит_6 в  ADCSRA оказывается напротив "1" и теперь он станет "1" не зависимо от того каким он был до этого !

т.е. смысл рассматриваемой строки программы 

ADCSRA|=0x40;

"установить" (т.е. сделать "1") бит_6  в  регистре ADCSRA

     
 

Число справа от составных операторов      |=   &=   ^= обычно называют маской

и говорят "наложить маску" - так как в результате меняются лишь те биты которые нужно изменить.

 
 

 

 


Для обнуления нужных бит используют обозначаемое знаком 
& поразрядное логическое И   -  только "1" и "1" дает "1"

PEREM &=(~0x04); // обнулить бит_2 в переменной PEREM

Скобки здесь я добавил для улучшения читаемости кода.

Самоконтроль - важно:

а) обязательно разберитесь почему обнуляется бит_2

б) Как в двоичном виде выглядит результат  (~0x04) 

 

     
 

 /* п.6     функции используемые в программе */

// их может быть столько сколько вам нужно.

// у нас будет одна, кроме main и 
// обработчика прерывания.

/*  =================================

Это будет функция в которой описано начальное 
конфигурирование МК в соответствии с 
поставленной задачей 

Удобно над функцией сделать заголовок
подробно поясняющий назначение функции !


=====================================  */

(void)__init_mk(void) {
/* Вначале любой функции объявляются 
ЛОКАЛЬНЫЕ ПЕРЕМЕННЫЕ - если конечно они вам нужны */

/* void - означает пусто. 

Перед названием функции - void - означает что функция не возвращает ни какого значения. А в скобках после названия означает что при вызове в функцию не передаются ни какие значения.  */

// инициализация Port_B 
DDRB=0xFF;  // все ножки сделать выходами
PORTB=0xFF;
// вывести на все ножки "1"

 

/* настройка АЦП - производится записью определенного числа в регистр "ADC Control and Status Register A" – ADCSRA

посмотрите его описание в ДШ МК мега16.

Нам нужно: 

- Включить модуль АЦП

- Установить допустимую частоту тактирования АЦП при частоте кварца 3.69 МГц  - мы выберем коэф. деления 64 - это даст частоту такта для процессов в АЦП  57.656 КГц

- Включить прерывание по завершению АЦ преобразования.

По ДШ для этого нужно записать в регистр ADCSRA
число:  1000 1110  или 0х8E  */

// ADC initialization w Oscillator=3.69MHz
// ADC Clock frequency: 57.656 kHz
// ADC Interrupts: On

ADCSRA=0x8E;

 

/* Теперь выбираем вход АЦП ADC0 (ножка PA0) и внешнее опорное напряжение (это напряжение код АЦП которого будет 1023) с ножки AREF 

Смотрим что нужно записать для этого в регистр 
мультиплексора (выбора входа) АЦП ADMUX  

см. ДШ
*/ 

// Нужно записать 0 (он там по-умолчанию)
ADMUX=0;



/* Разрешаем ГЛОБАЛЬНО все прерывания 
      разрешенные индивидуально ! 

Вы наверно поняли что индивидуально мы разрешили 
лишь прерывание по завершении АЦП - вот оно то и 
сможет возникать у нас.  */

#asm("sei")

 
     

 

Внимание ! так делаются вставки ассемблерных инструкций:

#asm("инструкция на ассемблере")

Обратите внимание - точки с запятой НЕТ ! Такие вставки принято иногда делать  НО они не являются необходимыми,  На   Си   можно управлять ВСЕМИ программно изменяемыми битами в регистрах МК !

     
 

Напоминаю ...    Все регистры МК перечислены в конце ДШ с указанием номеров страниц с подробным описанием регистра и его битов.

 
 

 

 

 

Но почему-то часто используются такие строки:

#asm("sei") // Разрешить ГЛОБАЛЬНО все прерывания

#asm("cli") // Запретить ГЛОБАЛЬНО все прерывания

#asm("nop") // Пауза в 1 такт процессора 

#asm("wdr") // Сбросить сторожевой таймер

     
 

// все функция закончена
} // скобка закрывающая для функции __init_mk() 

 
     


Далее...

     
 

/* 
п.7    главная функция  main()  - обязательная ! 
*/

/*  =================================
Главная функция - 

Си программа начинает выполнятся с нее!

=====================================  */

void main(void){
/* Вначале любой функции объявляются 
   (если нужны)  ЛОКАЛЬНЫЕ ПЕРЕМЕННЫЕ  */

__init_mk();/*Вызываем функцию инициализации, настроийки аппаратуры МК. Выполнив ее программа вернется сюда и будет выполнять 
следующую строку  */

// запускаем первое АЦП 
ADCSRA|=0x40;

// бесконечный цикл в ожидании прерываний 
while(1);
/* Программа будет крутится на этой строчке постоянно проверяя истинно ли условие в 
скобках после while а так как там константа 
1 - то условие будет истинно всегда!

  // функция main закончена
} // скобка закрывающая для функции main() 

 
     

 

Теперь программа будет работать так : 

По завершении АЦП будет возникать прерывание и программа будет перескакивать в функцию обработчик прерывания  adc_isr(), при этом будут автоматически запрещены все прерывания ГЛОБАЛЬНО !В конце  adc_isr() запускается новое АЦ преобразование и при выходе из обработчика прерывания снова разрешаются глобально прерывания, и программа возвращается опять в бесконечный цикл  while(1) .Такая чехарда будет продолжаться пока есть питание МК и не будет сброса.  Светодиоды будут высвечивать 8-ми битный код АЦП напряжения на ножке PA0  

Еще щепотка  Си :

Пример:  делать что-то  пока на ножке PBn есть "1" 

while(PINB & (1 << n)){
                       
что-то    
/* что-то будет выполнятся снова и снова, пока проверка условия в скобках после while будет давать "истину" - значит пока на ножке PBn есть логическая единица  */
                                              };

примечание  -  в CVAVR можно написать проще  
while(PINB.n){

Пример:  выполнить что-то если  на ножке PCn есть "0" 

if((~PINC)&(1 << n)){
                    
что-то
                                       /* что-то начнет выполняться если 
                     на ножке
PCn был "0" */
                                               };

примечание  -  в CVAVR можно написать проще  
while(!(PINB.n)){


Помните !     
Выполнение  чего-то  может быть прервано прерыванием.
После завершения обработки прерывания выполнение чего-то продолжится.

 

примечание  -

Условие : 

if((~PINC)&(1 << n)) {

можно записать и вот так : 

if(!(PINC & (1 << n))) {

 

     
 

К  битам  регистров с адресами от 0 до 31 в компиляторе CodeVisionAVR можно обратится (и читать и записывать) проще.

Вот так:     REGISTR.BIT  

 
 

 

 

Пример:   PINB.2   или   PORTA.5 

Пример:
if(!PINB.2){

                этот код /* Если на ножке PB2 низкий 
логический уровень - то выполнить
этот код */
                            };   

Пример:
PORTA.3 = 1; /* Сделать бит 3 в регистре 
PORTA единицей - говорят: "установить бит" 
по англ. "set bit" */

     
 

Битовые операции подробно описаны в задаче 1 и конечно в  help  компиляторов ! 

 
 

 

 

 

Всё программа на Си написана. Вам должно быть все ясно и  абсолютно понятно. Если это не так то перечитайте, подумайте, повторите разбор, почитайте рекомендованное ниже по Си.

Теперь вы должны знать 

  • - как записать число в регистр, в переменную 

  • - как изменить бит в регистре  

  • - как взять число из регистра

  • - как выполнить что-то в зависимости от значения бита в регистре или в переменной

 

Попробуйте поискать полезную инормацию в Гугле - ее там море !  Учитесь искать!

 

Язык Си - дополнительная литература


Очень доступно о Си рассказано здесь: 

Андрей Богатырев. Руководство полного идиота
по программированию на языке Си
 

обязательно используйте его при работе! и заглядывайте в него. 

  Статья "Си без Си" уважаемого и очень опытного микроконтроллерщика - ник: Bill http://www.caxapa.ru/story/bill_1.html

Очень советую вот это:  

Ю.Ю.Громов, С.И.Татаренко

ПРОГРАММИРОВАНИЕ НА ЯЗЫКЕ СИ

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

Учебное пособие предназначено для студентов всех специальностей, аспирантов и инженерно-технических работников использующих вычислительную технику. 

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

 

ОГЛАВЛЕНИЕ

1.ОПИСАНИЕ ЯЗЫКА СИ

1.1. ЭЛЕМЕНТЫ ЯЗЫКА СИ
1.1.1. Используемые символы
1.1.2. Константы
1.1.3. Идентификатор
1.1.4. Ключевые слова
1.1.5. Использование комментариев в тексте программы

1.2. ТИПЫ ДАННЫХ И ИХ ОБ ЯВЛЕНИЕ
1.2.1 Категории типов данных
1.2.2. Целый тип данных
1.2.3. Данные плавающего типа
1.2.4. Указатели
1.2.5. Переменные перечислимого типа
1.2.6. Массивы
1.2.7. Структуры
1.2.8. Объединения (смеси)
1.2.9. Поля битов
1.2.10. Переменные с изменяемой структурой
1.2.11. Определение объектов и типов
1.2.12. Инициализация данных

1.3. ВЫРАЖЕНИЯ И ПРИСВАИВАНИЯ
1.3.1. Операнды и операции
1.3.2. Преобразования при вычислении выражений
1.3.3. Операции отрицания и дополнения
1.3.4. Операции разадресации и адреса
1.3.5. Операция sizeof
1.3.6. Мультипликативные операции
1.3.7. Аддитивные операции
1.3.8. Операции сдвига
1.3.9. Поразрядные операции


1.3.10. Логические операции

 

     
 

Я обнаружил ошибку в разделе 1.3.10 

правильно вот так: 

Операция логического И (&&) вырабатывает значение 1 если оба операнда имеют НЕнулевые значения.

 
 

 

 


1.3.11. Операция последовательного вычисления
1.3.12. Условная операция
1.3.13. Операции увеличения и уменьшения
1.3.14. Простое присваивание
1.3.15. Составное присваивание
1.3.16. Приоритеты операций и порядок вычислений
1.3.17. Побочные эффекты
1.3.18. Преобразование типов

1.4. ОПЕРАТОРЫ
1.4.1. Оператор выражение
1.4.2. Пустой оператор
1.4.3. Составной оператор
1.4.4. Оператор if
1.4.5. Оператор switch
1.4.6. Оператор break
1.4.7. Оператор for
1.4.8. Оператор while
1.4.9. Оператор do while
1.4.10. Оператор continue
1.4.11. Оператор return
1.4.12. Оператор goto

1.5. ФУНКЦИИ
1.5.1. Определение и вызов функций
1.5.2. Вызов функции с переменным числом параметров
1.5.3. Передача параметров функции main

1.6. СТРУКТУРА ПРОГРАММЫ И КЛАССЫ ПАМЯТИ
1.6.1. Исходные файлы и объявление переменных
1.6.2. Объявления функций
1.6.3. Время жизни и область видимости программных объектов
1.6.4. Инициализация глобальных и локальных переменных

1.7. УКАЗАТЕЛИ И АДРЕСНАЯ АРИФМЕТИКА
1.7.1. Методы доступа к элементам массивов
1.7.2. Указатели на многомерные массивы
1.7.3. Операции с указателями
1.7.4. Массивы указателей
1.7.5. Динамическое размещение массивов

1.8. ДИРЕКТИВЫ ПРЕПРОЦЕССОРА
1.8.1. Директива #include
1.8.2. Директива #define
1.8.3. Директива #undef

2. ОРГАНИЗАЦИЯ СПИСКОВ И ИХ ОБРАБОТКА

2.1. ЛИНЕЙНЫЕ СПИСКИ
2.1.1. Методы организации и хранения линейных списков
2.1.2. Операции со списками при последовательном хранении
2.1.3. Операции со списками при связном хранении
2.1.4. Организация двусвязных списков
2.1.5. Стеки и очереди
2.1.6. Сжатое и индексное хранение линейных списков

2.2. СОРТИРОВКА И СЛИЯНИЕ СПИСКОВ
2.2.1. Пузырьковая сортировка
2.2.2. Сортировка вставкой
2.2.3. Сортировка посредством выбора
2.2.4. Слияние списков
2.2.5. Сортировка списков путем слияния
2.2.6. Быстрая и распределяющая сортировки

2.3. ПОИСК И ВЫБОР В ЛИНЕЙНЫХ СПИСКАХ
2.3.1. Последовательный поиск
2.3.2. Бинарный поиск
2.3.3. М-блочный поиск
2.3.4. Методы вычисления адреса
2.3.5. Выбор в линейных списках

2.4. РЕКУРСИЯ

Чтение по порядку глав

 

Вообще сайт СитФорум по программированию ПК рулит!


Повторю:  

Отличное руководство по Си для AVR это HELP в компиляторе CodeVisionAVR 

Читайте его и ищите в нем интересующее вас по ключевым словам.

Добавить страницу в закладки:

 

<- Назад                            Дальше->
 
 



 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

 

Rating All.BY Rambler's Top100 ћ≈“ј - ”краина. –ейтинг сайтов



Copyright 2009-2019 123avr.com