Презентация на тему: Программирование на Си в среде CCS

Реклама. Продолжение ниже
Программирование на Си в среде CCS
Язык Си
Программа на Си
Программа на Си
Главная функция
Оператор присваивания
Объявление переменных
Объявление переменных
Имена переменных
Типы данных языка Си для TMS320x28xx
Объявление массивов
Структуры
Структуры
Инициализация структур
Операции языка Си
Арифметические операции
Инкрементирование и декрементирование
Пост- и пред- инкремент
Операция деления
Управление ходом вычислений
if else
if else
else if
Критерий истинности условия оператора « if »
Операции сравнения
Логические операции
Поразрядные логические операции
Поразрядные логические операции
Пример использования логических операторов
Приоритеты логических операций
Цикл while
Цикл do while
Цикл for
Цикл for
switch и break
Оператор switch и break
Наша первая программа на Си
Функции
Формат функции
Вызов функции
Аргументы функции
Указатели
Операции с указателями
Указатели
Указатели - пример
Указатели - пример
Указатели - пример
Указатели и массивы
Указатели и структуры
Указатели и функции
Указатели и функции
Определение функций в отдельном файле
Квалификатор extern
Заголовочные файлы.h
Подключаемые файлы
Пример создания внешнего модуля
Пример создания внешнего модуля
Пример создания внешнего модуля
Пример создания внешнего модуля
Пример создания внешнего модуля
Пример создания внешнего модуля
Пример создания внешнего модуля
Пример создания внешнего модуля
Пример создания внешнего модуля
Пример заголовочного файла
Включаемые функции
Включаемые функции
Директива #define
Директива #define
Директива #define
Методы условной компиляции. # ifdef и # ifndef
Методы условной компиляции.
Методы условной компиляции.
Использование оптимизатора
Использование оптимизатора
Использование оптимизатора
Использование оптимизатора
Использование оптимизатора
Использование оптимизатора
Использование оптимизатора
Использование оптимизатора
Опасность оптимизации
Использование оптимизатора
Использование оптимизатора
Оптимизация переменных
Оптимизация переменных
Оптимизация переменных
Спасибо за внимание
1/88
Средняя оценка: 4.1/5 (всего оценок: 90)
Код скопирован в буфер обмена
Скачать (5220 Кб)
Реклама. Продолжение ниже
1

Первый слайд презентации: Программирование на Си в среде CCS

Изображение слайда
Изображение для работы со слайдом
1/2
2

Слайд 2: Язык Си

Язык высокого уровня Низкоуровневые механизмы обращения с данными Оптимально преобразуется в объектный исполняемый код Широкое распространение Очень большая поддержка

Изображение слайда
1/1
3

Слайд 3: Программа на Си

/* объявление переменных */ int a ; // описание первого слагаемого int b ; // описание второго слагаемого int c ; // описание результата (суммы) /* основная программа */ void main () /* главная функция программы */ { // текст программы – подсчёт суммы двух чисел a = 10; b = 5; c = a + b ; // подсчёт суммы двух чисел }

Изображение слайда
1/1
4

Слайд 4: Программа на Си

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

Изображение слайда
1/1
5

Слайд 5: Главная функция

/* основная программа */ void main () /* главная функция программы */ { /* текст программы – подсчёт суммы двух чисел */ a = 10; b = 5; c = a + b ; // подсчёт суммы двух чисел } Функция « main » является главной функцией программы. Она обязательно должна присутствовать в проекте. После того, как будет выполнен код инициализации микроконтроллера и глобальных переменных программы, управление будет передано этой функции. Можно сказать, что выполнение пользовательской программы начинается с этой функции.

Изображение слайда
1/1
6

Слайд 6: Оператор присваивания

Оператор присваивания – «=». Записывает в переменную значение. Кроме того существует понятие «составного присваивания»: выполнить действие с переменной и сохранить результат в эту же переменную: x = x + 5 можно записать как x+=5 y = y – 2 можно записать как y-=2

Изображение слайда
1/1
7

Слайд 7: Объявление переменных

/* объявление переменных */ int a ; // описание первого слагаемого int b ; // описание второго слагаемого int c ; // описание результата (суммы) /* объявление переменных */ int a, b, c ; Сначала указывается тип переменной, затем её имя. Можно объявить несколько переменных одного типа через запятую.

Изображение слайда
1/1
Реклама. Продолжение ниже
8

Слайд 8: Объявление переменных

При объявлении переменной можно сразу её проинициализировать. В таком случае, к началу выполнения программы (функции « main » ) её значение будет известно. Если переменную не проинициализировать, то к началу выполнения программы в ней может лежать что угодно – «мусор».

Изображение слайда
Изображение для работы со слайдом
1/2
9

Слайд 9: Имена переменных

Состоят из букв и цифр Первый символ – всегда буква Символ «_» считается буквой Строчные буквы для имен переменных Заглавные для символических констант Нельзя использовать в качестве имен зарезервированные слова ( if, else, for...)

Изображение слайда
1/1
10

Слайд 10: Типы данных языка Си для TMS320x28xx

Тип Размер Минимум Максимум char 16 бит -32768 32767 unsigned char 16 бит 0 65535 short 16 бит -32768 32767 unsigned short 16 бит 0 65535 int 16 бит -32768 32767 unsigned int 16 бит 0 65535 long 32 бита -2147483648 2147483647 unsigned long 32 бита 0 4294967295 enum 16 бит -32768 32767 float 32 бита -1,19E-38 1,19E+38 double 32 бита -1,19E-38 1,19E+38 long double 32 бита -1,19E-38 1,19E+38

Изображение слайда
1/1
11

Слайд 11: Объявление массивов

Массив – последовательность элементов одного типа в памяти. Синтаксис объявления массива: сначала указывается типа элементов массива, затем имя, а после имени в квадратных скобках – количество элементов. Нумерация элементов начинается с «0» // Объявление массива « a » из 100 элементов типа " int " int a [100]; void fillBuf ( void ){ a [0] = 5; // Записать число "5" в первый элемент массива a [1] = 6; // Записать число "6" во второй элемент массива }

Изображение слайда
1/1
12

Слайд 12: Структуры

Структуры позволяют сгруппировать несколько переменных разных типов. Также среди членов структуры могут быть указатели на переменные и указатели на функции. Пример описания структуры : // Пример описания структуры с элементами разных типов struct myStruct { int mem1 ; unsigned long mem2 ; long * pmem3 ; void (* someFunc )(); };

Изображение слайда
1/1
13

Слайд 13: Структуры

Использование структур удобно, когда нужно задать несколько объектов, имеющий одинаковые свойства. Например – каналы АЦП, которые имеют коэффициент усиления, смещение сигнала, код АЦП, результат преобразования и т.д. Один контроллер может поддерживать 10 – 15 каналов АЦП, что может дать 45 переменных. // Структура-описатель канала АЦП struct adcChannel { // Коэфф. усиления int gain ; // Смещение сигнала int offset ; // Результат оцифровки int result ; // Функция очистки данных void (* clear )(); }; void main ( void ) { // Создать структуры для обработки АЦП struct adcChannel Udc ; // Напр. ЗПТ struct adcChannel Ia, Ib, Ic ; // Фазные токи // Настройка канала АЦП Udc. gain = 540; Udc. offset = 0; }

Изображение слайда
1/1
14

Слайд 14: Инициализация структур

Структуру можно инициализировать двумя способами: Присвоить разные значения каждому элементу Присвоить всем элементам одно и то же значение Значения для инициализации приводятся после знака « = » в фигурных скобках: // Определение структуры даты struct Sdate { int year, month, day, dayOfWeek ; int hour, minute, second ; }; // Создание экземпляра. Каждый элемент инициализирован своим значением struct Sdate dateOfBirth = {1980, 11, 21, 4, 13, 24, 11}; // Все элементы инициализированы значением "0" struct Sdate dateOfDeath = {0};

Изображение слайда
1/1
Реклама. Продолжение ниже
15

Слайд 15: Операции языка Си

Арифметические Сравнения Логические Поразрядные логические Присваивания

Изображение слайда
1/1
16

Слайд 16: Арифметические операции

Оператор Операция + Сложение - Вычитание * Умножение / Деление % Остаток от деления ++ Инкремент -- Декремент

Изображение слайда
1/1
17

Слайд 17: Инкрементирование и декрементирование

Инкремент – увеличение значения переменной на 1 Декремент – уменьшение значения переменной на 1 Различают пред-инкремент и пост-инкремент: x ++; // x увеличивается на 1 после использования x --; // x уменьшается на 1 после использования ++ x ; // x увеличивается на 1 перед использованием -- x ; // x уменьшается на 1 перед использованием

Изображение слайда
1/1
18

Слайд 18: Пост- и пред- инкремент

void main( void ) { a = 10; b = a ++; // Сначала в b будет записано значение переменной а, // а затем "а" будет увеличена на 1. // В результате получится b = 10, a = 11 } Постинкремент : сначала с переменной производятся все действия, описанные в выражении, после чего её значение увеличивается на 1. void main( void ) { a = 10; b = ++ a ; // Сначала "а" будет увеличена на 1, // а затем в "b" будет записано значение переменной "а". // В результате получится b = 11, a = 11 } Прединкремент : перед началом всех действий переменная увеличивается на 1, а затем это увеличенное значение используется в выражении.

Изображение слайда
1/1
19

Слайд 19: Операция деления

При делении одного целого числа на другое результат получается ЦЕЛЫЙ, дробная часть отсекается: void main( void ) { int a = 5; int b = 2; int c ; // Так как переменные "a", "b", "c" - целые (имеют тип int ), // результат их деления также будет целым, без учёта остатка // Таким образом с = 2 c = a / b ; }

Изображение слайда
1/1
20

Слайд 20: Управление ходом вычислений

if else switch while do while for break continue

Изображение слайда
1/1
21

Слайд 21: if else

if ( выражение) инструкция1 else инструкция2 Иногда надо выбрать тот или иной вариант действий в зависимости от некоторых условий: если условие верно, поступать одним способом, а если неверно — другим. Для этого применяют условные операторы. Один из них – « if … else » - имеет следующий вид:

Изображение слайда
1/1
22

Слайд 22: if else

void checkCommands ( void ) { // Если пришла команда на выключение, // остановить привод, иначе пересчитать напряжение фаз if ( commandStop == 1) { stopDrive (); } else { updateVoltages (); } } Пример использования: В общем случае часть « else {…} » может отсутствовать. В теле оператора « if » или « else » может выполняться одно действие (как в примере выше), а может несколько. Если выполняется только одно действие, то фигурные скобки ставить не нужно, но всё равно рекомендуется.

Изображение слайда
1/1
23

Слайд 23: else if

void main( void ) { // Если пришла команда на включение, подготовить и // запустить привод; иначе, если пришла команда на // остановку, остановить привод. Иначе повторно // запросить команды if ( commandStart == 1) { clearAllFaults (); startDrive (); updateVoltages (); } else if ( commandStop == 1) { stopDrive (); setZeroVoltage (); } else { requestCommands (); } } Также можно проверять несколько разных условий при помощи дополнительных блоков « else if (…) ». Можно использовать сколько угодно таких проверок. В это случае будут выполнены только те действия, которые находятся внутри блока, условие которого истинно. Если истинны условия сразу в нескольких блоках, то будет выполнен только первый.

Изображение слайда
1/1
24

Слайд 24: Критерий истинности условия оператора « if »

Истинным считается любое значение, не равное нулю: if (4) doCase1 (); else if (100 / 8) doCase2 (); Более привычным условием для оператора считается результат сравнения двух чисел/переменных: // Если скорость двигателя меньше 100 об/мин, // увеличить скорость; а если больше - уменьшить if ( driveSpeed < 100) driveSpeed += 5; else if ( driveSpeed > 100) driveSpeed -= 5;

Изображение слайда
1/1
25

Слайд 25: Операции сравнения

Оператор Операция > Больше чем >= Больше или равно < Меньше чем <= Меньше или равно == Равно != Не равно

Изображение слайда
1/1
26

Слайд 26: Логические операции

Оператор Операция && И || Или ! Не, отрицание

Изображение слайда
1/1
27

Слайд 27: Поразрядные логические операции

Оператор Операция & побитовое И | побитовое Или ^ Исключающее Или ~ побитовое Не >> Сдвиг вправо << Сдвиг влево

Изображение слайда
1/1
28

Слайд 28: Поразрядные логические операции

Следует различать операции « && » и « & ». Логическое И (« && ») даёт результат «истина», когда оба операнда не равны 0, иначе даёт результат «ложь». Результат такой операции, как правило, используется только для условного ветвления программы («если ( А && В ), то выполнить действие_1»). Побитовое И (« & ») даёт результат операции «И» между соответствующими битами переменных. Используется для различных целей, например для наложения маски:

Изображение слайда
Изображение для работы со слайдом
1/2
29

Слайд 29: Пример использования логических операторов

Операторы «логическое И» и «логическое ИЛИ» используются, когда какое-то действие нужно выполнить в том случае, когда выполняется сразу несколько условий (в случае оператора И) или, наоборот, хотя бы одно из условий (в случае оператора ИЛИ): // Если нет аварий, задание скорости не нулевое // и есть команда запуска - запустить привод // А если есть авария или команда "стоп" - остановить if ( faultCounter == 0 && speedReference != 0 && commandStart == 1) { startDrive (); } else if ( faultCounter != 0 || commandStop == 1) { stopDrive (); }

Изображение слайда
1/1
30

Слайд 30: Приоритеты логических операций

Приоритет у « && » выше чем у « || » и обе они младше операций отношения и равенства. Выражение вычисляется в порядке приоритетов. Если результат выражения оказывается известен до окончания вычислений, то вычисления прекращаются. Это следует учитывать при программировании. Операции отношения имеют приоритет перед операциями проверки равенства. Арифметические операции старше операций отношения: a < b – 1 эквивалентно a < (b – 1)

Изображение слайда
1/1
31

Слайд 31: Цикл while

Цикл « while » имеет следующий формат вызова: while ( выражение) { инструкции } Вычисляется выражение. Если его значение равно «истине», то выполняется инструкция. Этот цикл будет выполняться, пока выражение не станет ложным, после чего вычисления продолжатся с точки сразу за инструкцией. // Вычитывание данных из массива до тех пор, // пока он не опустеет while ( bufferEmptyFlag == 0) { readDataFromBuffer (); bufferEmptyFlag = checkBuffer (); }

Изображение слайда
1/1
32

Слайд 32: Цикл do while

Цикл « do while » имеет следующий формат вызова: do инструкция while ( выражение) Выполняется инструкция. Вычисляется выражение. Если его значение равно «истине», то цикл будет выполняться. Отличается от цикла while() тем, что «инструкция» гарантированно будет выполнена хотя бы один раз, даже если «выражение» ложно. // Пока не будет заполнен весь массив, // заполнять его случайными числами do { // Записать в элемент с номером " counter " случайное число buffer [ counter ] = randomNumber (); // Увеличить счётчик элементов counter ++; } while ( counter < bufferSize );

Изображение слайда
1/1
33

Слайд 33: Цикл for

Цикл « for » имеет следующий формат вызова: for ( выражение1; выражение2; выражение3) { инструкция 1; } Выражение1 выполняется только один раз, затем проверяется выражение2, и если оно истинно, выполняются инструкции. После выполнения всех инструкций выполняется выражение3. Затем проверяется выражение2, и если оно истинно выполняются инструкции и так далее. Что эквивалентно конструкции: выражение1; while ( выражение2) { инструкция 1 ; выражение3 ; }

Изображение слайда
1/1
34

Слайд 34: Цикл for

Цикл « for » обычно используется в тех случаях, когда заранее известно количество итераций. Наиболее часто для работы с массивами. В данном примере объявляется вспомогательная переменная « i », которая используется для перебора элементов массива. В цикле « for » эта переменная вначале обнуляется ( выражение1: I = 0 ), затем проверяется условие, что конец массива не достигнут ( выражение2: i < bufferSize ), затем обнуляется элемент массива с номером i. После этого переменная i инкрементиуется ( выражение3: i ++ ). Таким образом все элементы массива от 0 до 99 будут обнулены. // Очистить массив элементов int i ; for ( i = 0; i < bufferSize ; i ++) { buffer [ i ] = 0; }

Изображение слайда
1/1
35

Слайд 35: switch и break

Оператор « switch » позволяет выполнять те или иные действия, в зависимости от значения переменной. Синтаксис оператора: switch ( переменная) { case значение1: инструкция1; break; case значение 2 : инструкция 2 ; break; case значение 3 : инструкция 3 ; break; }

Изображение слайда
1/1
36

Слайд 36: Оператор switch и break

// В зависимости от значения переменной driveMode, // запустить тот или иной алгоритм управления switch ( driveMode ){ case 0: scalarMode (); break ; case 1: vectorMode (); break ; case 2: slowDown (); break ; default : doNoting (); break ; }

Изображение слайда
1/1
37

Слайд 37: Наша первая программа на Си

/* Наша первая программа на языке СИ */ /* Определение и инициализация глобальных переменных */ int x = 2; int y = 7; /* Основная программа */ void main ( void ){ // Определение локальной переменной long z ; // Секция выполнения – бесконечный цикл for ( ; ; ){ z = x ; z = z + y ; //Вычисление переменной z } }

Изображение слайда
1/1
38

Слайд 38: Функции

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

Изображение слайда
1/1
39

Слайд 39: Формат функции

тип_результата имя_функции ( список_аргументов ) { тело функции } // Функция возведения переменной в степень // Аргументы: x - число, которое нужно возвести // pow - требуемая степень long power ( int x, unsigned int pow ) { unsigned int i ; // Вспомогательная переменная long result = x ; // Результат // Умножаем результат на х столько раз, // сколько требуется for ( i = 1; i < pow ; i ++){ result = result * x ; } // Возвращаем результат return result ; }

Изображение слайда
1/1
40

Слайд 40: Вызов функции

void main( void ) { int varA = 20; unsigned int powerA = 8; long res ; // Записать в res число, которое вернёт вернёт функция power // В результате получится res = varA в степени powerA res = power ( varA, powerA ); } Чтобы вызвать функцию, необходимо написать её имя и передать соответствующие аргументы. В примере выше функция называлась « power » и принимала два аргумента. Типы переменных которые передаются в функцию должны соответствовать типам аргументов. Это также касается и результата.

Изображение слайда
1/1
41

Слайд 41: Аргументы функции

Переменные, которые передаются в функцию в качестве аргументов не меняются внутри функции, как бы она не была устроена внутри. Когда в функцию передаются переменные, то внутри неё временно создаются их копии, и вся работа внутри функции происходит с копиями. // Функция умножения числа на 100 int multiple100 ( int x ) { // Чтобы не занимать стек локальными переменными, // не будем создавать переменную " result ", а изменим // само значение аргумента: x = x * 100; return x ; } void main( void ) { int varA = 20; int varB ; // Умножим переменную varA на 100 и запишем результат в varB varB = multiple100 ( varA ); // В результате этой операции varB = 20000, // А значение varA не изменится: varA = 20 }

Изображение слайда
1/1
42

Слайд 42: Указатели

Си поддерживает низкоуровневое неконтролируемое обращение к памяти с помощью указателей. int *px ; Данная строка кода создаст переменную типа указатель. То есть px хранит в себе адрес, а * px – содержимое, размещенное по этому адресу. // Объявить переменную varA и указатель, который пока что // не указывает ни на какую переменную int varA = 1; int * pointerVarA ; void main( void ) { // Записать в указатель " pointerVarA " адрес переменно varA // Символ "&" означает "получить адрес" pointerVarA = & varA ; }

Изображение слайда
1/1
43

Слайд 43: Операции с указателями

Основные операции над указателями: увеличение (инкремент), уменьшение (декремент) и присваивание. Увеличить или уменьшить указатель можно не только операциями инкремента/декремента, но и сложением с константой. Важно понимать, что инкрементирование/декрементирование указателя меняет его значение так, чтобы он указывал на следующий/предыдущий элемент. Таким образом, если указатель px указывает на переменную x типа int, которая занимает 1 ячейку памяти, то операция « px ++ » увеличит значение указателя на 1. А если бы переменная x имела тип long, который требует 2 ячейки памяти, то та же операция увеличила бы указатель px на 2. Поэтому тип указателя должен совпадать с типом переменной, на которую он указывает. То есть указатель, который объявлен как « int *p », не может указывать на переменную, которая объявлена как « long x ».

Изображение слайда
1/1
44

Слайд 44: Указатели

Также через указатель можно получить значение, которое хранится в той ячейке, на которую он указывает, при помощи оператора « * »: // Объявить переменные varA, varB и указатель, который пока что // не указывает ни на какую переменную int varA = 1, varB ; int * pointer ; void main( void ) { // Записать в указатель " pointerVarA " адрес переменно varA // Символ "&" означает "получить адрес" pointer = & varA ; // Теперь запишем в переменную varB значение, которое хранится // в ячейке памяти, на которую указывает pointer : varB = * pointer ; // Так как pointer указывал на переменную varA, то теперь // varB имеет такое же значение: varB = 1 }

Изображение слайда
1/1
45

Слайд 45: Указатели - пример

Выполнение программы из предыдущего слайда. Шаг первый: переменная « varA » находится по адресу 0x8807, Указатель « pointer » пока что указывает на какую-то случайную ячейку

Изображение слайда
Изображение для работы со слайдом
1/2
46

Слайд 46: Указатели - пример

Шаг второй: в указатель « pointer » записан адрес переменной « varA »

Изображение слайда
Изображение для работы со слайдом
1/2
47

Слайд 47: Указатели - пример

Шаг третий: в переменную « varB » записано значение ячейки памяти, на которую указывал « pointer ». Т.к. он указывал на переменную « varA », то значение « varB » теперь равно значению « varA ».

Изображение слайда
Изображение для работы со слайдом
1/2
48

Слайд 48: Указатели и массивы

int inputBuf [100]; int * input ; int x, y ; void main(){ // Имя массива является указателем на его первый элемент // Следующие две строки идентичны input = inputBuf ; input = & inputBuf [0]; // В переменную x запишется первый элемент массива, // а в y - второй x = * input ; y = *( input + 1); x = inputBuf [0]; y = inputBuf [1]; } Указатели часто используются для перебора массивов

Изображение слайда
1/1
49

Слайд 49: Указатели и структуры

struct my_time systime ; // Структура struct my_time * t ; // Указатель на структуру void main ( void ) { // Доступ к элементу структуры через имя экземпляра systime. hours = 1; // Доступ к элементу структуры через указатель t -> hours = 1; } Также может быть создан указатель на структуру. В таком случае указатель хранит адрес первого элемента структуры. При обращении к элементам структуры через указатель, используется оператор « - > » вместо «. »

Изображение слайда
1/1
50

Слайд 50: Указатели и функции

Иногда удобно передавать данные в функцию через указатели. Это удобно, когда необходимо возвращать значения сразу нескольких переменных. Например, если функция должна записать значение в переменную и вернуть какой-то результат своей работы: // Функция чтения значения из регистра int readValue ( long * x ){ // Если буфер пуст, вернуть -1 // Иначе записать значение и вернуть 0 if ( bufferEmpty == 1) { return -1; } else { * x = ethernetData ; return 0; } }

Изображение слайда
1/1
51

Слайд 51: Указатели и функции

void main ( void ) { int result, data ; // Вызываем функция, передавая в неё адрес переменной // Если функция была выполнена успешно - обрабатываем данные result = readValue (& data ); if ( result == 0) { processData (); } } Если аргументом функции является указатель, то передавать нужно адрес переменной, а не саму переменную. В этом случае, значение переменной будет изменено (в отличие от случая, когда передаётся сама переменная).

Изображение слайда
1/1
52

Слайд 52: Определение функций в отдельном файле

При создании проекта разными программистами или фирмами удобно создавать различные функции в разных исходных файлах. Такой подход позволяет получать готовые для компоновки объектные файлы, которые могут распространяться без перекомпиляции и раскрытия исходного кода. По умолчанию все функции Си являются глобальными. Если происходит вызов глобальной функции, то ее описание через прототип необязательно. Описание требуют только внешние переменные используемого модуля. Для этого создаются заголовочные файлы, содержащие информацию об объектном файле библиотеки.

Изображение слайда
1/1
53

Слайд 53: Квалификатор extern

Используется при модульном программировании extern volatile i nt x; ……………………………………………………… volatile int x =7; Этот квалификатор означает, что в одном из файлов определена переменная « x ». Если при объявлении выделяется память под переменную, то процесс называется определением. Использование extern приводит к объявлению, но не к определению. Оно просто говорит компилятору, что определение происходит где-то в другом месте программы. При описании переменной с этим квалификатором, под неё не выделяется места в памяти, но компилятор знает тип этой переменной и как правильно совершать с ней различные действия.

Изображение слайда
1/1
54

Слайд 54: Заголовочные файлы.h

Файл. h должен содержать полную информацию по используемому модулю. Хотя это и необязательно, но принято описывать прототипы функций модуля, чтобы программист, пользующийся модулем знал названия включенных в него функций и формат вызова каждой из них. Будучи включенным в программу, заголовочный файл должен описывать все, что может потребоваться программисту для обращения к функциям модуля и переменным как ко внутренним функциям проекта.

Изображение слайда
1/1
55

Слайд 55: Подключаемые файлы

Директива #include включает указанный файл в текущую позицию компилируемого файла. Имя файла заключается либо в « ” ” », либо в « < > ». Имя файла может содержать полный или частичный путь к файлу или не содержать пути. #include < stdio.h > #include “ main.h ” #include “C:\...\ main.h ” Фактически эта директива заменяется на содержимое включаемого файла.

Изображение слайда
1/1
56

Слайд 56: Пример создания внешнего модуля

Модуль должен производить суммирование двух целых чисел. Входными и выходными переменными являются переменные модуля. // Файл “ functions.c ” // Функция умножения // В качестве аргументов принимает два числа типа int // возвращает число типа long long mult ( int a, int b ) { return a * b ; } // Функция деления // В качестве аргументов принимает два числа типа int // возвращает число типа long long div ( int a, int b ) { return a / b ; }

Изображение слайда
1/1
57

Слайд 57: Пример создания внешнего модуля

Заголовочный файл: /* Заголовочный файл, в котором * описан интерфейс функций */ # ifndef FUNCTIONS_H_ #define FUNCTIONS_H_ long mult ( int, int ); long div ( int, int ); #endif /* FUNCTIONS_H_ */

Изображение слайда
1/1
58

Слайд 58: Пример создания внешнего модуля

Основная программа, использующая модуль: /* Пример модульного подхода к программированию */ /* Подключение заголовочного файла, в котором описаны интерфейсы функций */ #include " functions.h " /* Объявление переменных */ int x = 1; // Переменная типа " int " int y ; // Переменная типа " int " long z ; // Переменная типа " long " /* Главная функция. Содержит вызов двух других функций, * описанных в заголовочном файле " headers.h " */ void main( void ) { long q ; y = 3; z = mult ( x, y ); q = div ( x, y ); }

Изображение слайда
1/1
59

Слайд 59: Пример создания внешнего модуля

Изображение слайда
Изображение для работы со слайдом
Изображение для работы со слайдом
1/3
60

Слайд 60: Пример создания внешнего модуля

Изображение слайда
Изображение для работы со слайдом
1/2
61

Слайд 61: Пример создания внешнего модуля

Изображение слайда
Изображение для работы со слайдом
1/2
62

Слайд 62: Пример создания внешнего модуля

Изображение слайда
Изображение для работы со слайдом
1/2
63

Слайд 63: Пример создания внешнего модуля

Изображение слайда
Изображение для работы со слайдом
1/2
64

Слайд 64: Пример создания внешнего модуля

Изображение слайда
Изображение для работы со слайдом
1/2
65

Слайд 65: Пример заголовочного файла

/* ======================================================================== File name: CLARKE.H (IQ version) Originator: Digital Control Systems Group Texas Instruments Description: Header file containing constants, data type definitions, and function prototypes for the CLARKE History: 05-15-2002 Release Rev 1.0 */ typedef struct { _ iq as ; /* Input: phase-a stator variable */ _ iq bs ; /* Input: phase-b stator variable */ _ iq ds ; /* Output: stationary d-axis stator variable */ _ iq qs ; /* Output: stationary q-axis stator variable */ void (* calc )(); /* Pointer to calculation function */ } CLARKE ; typedef CLARKE * CLARKE_handle ; /*------------ Default initalizer for the CLARKE object. ---*/ #define CLARKE_DEFAULTS { 0, 0, 0, 0, ( void (*)( long )) clarke_calc } /*----------- Prototypes for the functions in CLARKE.C ---*/ void clarke_calc ( CLARKE_handle );

Изображение слайда
1/1
66

Слайд 66: Включаемые функции

Когда вызывается включаемая функция, то ее код вставляется непосредственно в то место программы, где она вызывается. Преимущества включаемых функций: Экономия времени на операциях вызова и возврата из функции Включенная функция может оптимизироваться компилятором совместно с окружающим ее кодом Типы включаемых функций: Встроенные операторы (встроенные операторы всегда включаемые (+, -, *, /...)) Автоматическое включение Управляемое включение при определении функции

Изображение слайда
1/1
67

Слайд 67: Включаемые функции

Включение функций осуществляется ключевым словом inline

Изображение слайда
Изображение для работы со слайдом
Изображение для работы со слайдом
1/3
68

Слайд 68: Директива #define

Директива #define является одной из директив препроцессора. Она позволяет создать макроопределение, которое можно использовать в коде программы. Перед компиляцией исходного файла выполняется препроцессинг, который обрабатывает директивы ( #define, #include, #pragma и другие). Во время препроцессинга все встречающиеся макроопределения в коде будут заменены на соответствующие значения. // Определить число Пи #define PI 3.1416 void main ( void ) { // Задать радиус и рассчитать площадь круга float radius = 4; float square = radius * radius * PI ; }

Изображение слайда
1/1
69

Слайд 69: Директива #define

Важно понимать, что макроопределение это не переменная. С помощью этой директивы можно определять не только константы, а любые конструкции. Потому что фактически препроцессор просто заменит имена макроопределений на их значения. В примере ниже слово « condition » будет заменено на набор условий: // Макроопределение сложного условия #define condition ( forceRun == 1) || \ (( startCommand > 0) && ( enableRun == 1) \ && (faults == 0)) void main ( void ) { // Проверить условие запуска двигателя: // либо есть команда принудительного запуска ( forceRun ), // Либо есть команда обычного запуска, при этом нет аварий // и работа разрешена if ( condition ) startDrive (); }

Изображение слайда
1/1
70

Слайд 70: Директива #define

#define condition ( startCommand == 1) void main ( void ) { if ( condition ) startDrive (); } void main ( void ) { if (( startCommand == 1)) startDrive (); } Исходный файл: После препроцессинга :

Изображение слайда
1/1
71

Слайд 71: Методы условной компиляции. # ifdef и # ifndef

Метод условной компиляции состоит в использовании директив # ifdef и # ifndef, что соответ­ственно означает «если определено» и «если не определено». Стандартный вид # ifdef следующий: # ifdef имя_макроса последовательность операторов # endif Если имя макроса определено ранее в операторе # define, то последовательность операторов, сто­ящих между # ifdef и # endif, будет компилироваться. Стандартный вид # ifndef следующий: # ifndef имя_макроса последовательность операторов # endif Если имя макроса не определено ранее в операторе # define, то последовательность операторов, стоящих между # if n def и # endif, будет компилироваться.

Изображение слайда
1/1
72

Слайд 72: Методы условной компиляции

Изображение слайда
Изображение для работы со слайдом
1/2
73

Слайд 73: Методы условной компиляции

Изображение слайда
Изображение для работы со слайдом
1/2
74

Слайд 74: Использование оптимизатора

Оптимизация «– o0 ». Оптимизация уровня регистров. Располагает переменные непосредственно в регистры Осуществляет оптимизацию циклов программы Удаляет неиспользованный программой код Упрощает арифметические выражения и выходную отчетность Вставляет в программу напрямую текст функций объявленных « inline » Используется если ваш модуль имеет функции, которые вызываются из других модулей и глобальные переменные, которые изменяются в других модулях.

Изображение слайда
1/1
75

Слайд 75: Использование оптимизатора

Оптимизация «– o 1». Выполняет те же действия, что при оптимизации «-о0», и дополнительно: осуществляет прямое присвоение локальных констант; удаляет неиспользованные присвоения переменных; исключает локальные повторяющиеся выражения; Оптимизация используется если Ваш модуль не имеет функций, которые вызываются другими модулями, но имеет глобальные переменные, которые изменяются в других модулях.

Изображение слайда
1/1
76

Слайд 76: Использование оптимизатора

Оптимизация «– o2 ». Выполняет те же действия, что и при оптимизации «-о 1 », и дополнительно: осуществляет улучшенную оптимизацию циклов; удаляет глобальные повторяющиеся подвыражения; исключает глобальные повторяющиеся присвоения; Оптимизатор использует «– o2 » по умолчанию, даже если вы не указали уровень оптимизации. Оптимизация используется если ваш модуль не имеет функций, которые вызываются другими модулями или глобальных переменных, которые изменяются в других модулях

Изображение слайда
1/1
77

Слайд 77: Использование оптимизатора

Оптимизация «– o3 ». Выполняет те же действия, что и при оптимизации «-о 2 », и дополнительно: удаляет все функции, которые не вызываются; упрощает функции результат вычислений ( присваивается return) которой не используется программой; напрямую без вызова вставляет небольшие функции указанные директивой « inline » перегруппирует описание функции, так чтобы атрибуты, вызываемой функции,

Изображение слайда
1/1
78

Слайд 78: Использование оптимизатора

Исходная программа:

Изображение слайда
Изображение для работы со слайдом
1/2
79

Слайд 79: Использование оптимизатора

Без оптимизации

Изображение слайда
Изображение для работы со слайдом
1/2
80

Слайд 80: Использование оптимизатора

Первый уровень оптимизации (- o0)

Изображение слайда
Изображение для работы со слайдом
1/2
81

Слайд 81: Использование оптимизатора

Второй уровень оптимизации (-о1) Компилятору очевидно, что &x != 0 x 00 FF всегда

Изображение слайда
Изображение для работы со слайдом
1/2
82

Слайд 82: Опасность оптимизации

Многие периферийные регистры изменяются не программным путём. Их состояние зависит от состояния дискретных входов и выходов микроконтроллера. Компилятор видит, что переменная, отвечающая за периферию, не изменяется ни в одном месте программы, и может исключить её обработку. Пример, когда возможна такая ситуация (состояние дискретного входа GPIO10 зависит от уровня сигнала на соответствующей ножке микроконтроллера):

Изображение слайда
Изображение для работы со слайдом
1/2
83

Слайд 83: Использование оптимизатора

Использование ключевого слова “volatile” защищает чтение и запись переменной от оптимизации

Изображение слайда
Изображение для работы со слайдом
Изображение для работы со слайдом
1/3
84

Слайд 84: Использование оптимизатора

Второй уровень оптимизации с использованием “volatile”

Изображение слайда
Изображение для работы со слайдом
1/2
85

Слайд 85: Оптимизация переменных

Использование статических переменных.

Изображение слайда
Изображение для работы со слайдом
Изображение для работы со слайдом
1/3
86

Слайд 86: Оптимизация переменных

Использование статических переменных.

Изображение слайда
Изображение для работы со слайдом
Изображение для работы со слайдом
1/3
87

Слайд 87: Оптимизация переменных

Статические переменные: не создаются при входе и не удаляются при выходе из функции (экономия процессорного времени) не расходуют пространство в стеке требуют больше памяти

Изображение слайда
1/1
88

Последний слайд презентации: Программирование на Си в среде CCS: Спасибо за внимание

Изображение слайда
1/1
Реклама. Продолжение ниже