Ускоренный курс языка Си

Структура программы

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

/* Включение заголовочных файлов */
#include <avr/io.h>
#include <stdio.h>
 
/* Макродекларации */
#define PI 3.141
 
/* Определение типа данных*/
typedef struct
{
	int a, b;
}
element;
 
/* Глобальные переменные */
element e;
 
/* Функции */
int main(void)
{	
	// Локальные переменные
	int x;
 
	// Программа
	printf("Здравствуй мир!\n");
}

Комментарии

Программисты могут вписывать текст для заметок или объяснений, который не компилируется. Также комментарии могут быть использованы для временного исключения программных отрезков. Примеры двух методов комментариев:

// Однострочный комментарий
// Комментарием считается текст, находящийся после двух наклонных черт
 
/*
  Многострочный комментарий
  Начало и конец комментария прописывается наклонными чертами и звёздочками
*/

 

Данные

Типы данных

Базовые типы данных языка Си:

Тип Минимум Максимум Bitte Baite
(signed) char -128 127 8 1
unsigned char 0 255 8 1
(signed) short -32768 32767 16 2
unsigned short 0 65535 16 2
(signed) long -2147483648 2147483647 32 4
unsigned long 0 4294967295 32 4
float -3.438 3.438 32 4
double -1.7308 1.7308 64 8

Слово “signed”, находящееся в скобках, использовать не обязательно, так как по умолчанию типы данных биполярные.

AVR на микроконтроллере int = short
На персональном компьютере int = long

На языке Си отсутствует специальный текстовой тип данных. Вместо этого используются массивы типа char (их описание последует далее) и «алфавит» ASCII, где у каждой буквы и знака имеется свой порядковый номер.

Переменные

В программе можно использовать определённые гнёзда для модуля памяти – переменные. Имена переменных могут содержать буквы латинского алфавита, номера и символ подчёркивания. Имя не может начинаться с цифры. При декларировании переменной перед ней пишется тип данных. При присвоении значения переменной используется знак равно (=). Пример использования переменных:

// декларирование переменной с типа char
char c;
 
// Присвоение c значения переменной.
c = 65;
c = 'A'; // A в системе знаков ASCII также имеет значение 65
 
// Декларирование и инициализация переменной типа int i20
int i20 = 55;
 
// Декларирование нескольких переменных типа unsigned short
unsigned short x, y, test_variable;

Константы

Константы декларируются также как и переменные, но перед типами данных добавляется ключевое слово const. Значения констант не меняются в течение программы. Пример использования:

// назначение константы типа int
const int x_factor = 100;

Структуры

При помощи ключевого слова struct можно формировать структуры из базовых типов данных. Структура является комбинированным типом данных. Тип декларируется ключевым словом typedef. Пример структуры при создании и использовании типа данных:

// Декларирование нового пункта типа данных
typedef struct
{
	// координаты x и y и цветовой код
	int x, y;
	char color;
}
point;
 
// Декларирование пункта переменной
point p;
 
// Задавание координат пункта
p.x = 3;
p.y = 14;

Массивы

Из типа данных можно создавать массивы. Массивы могут быть многомерными (таблица, куб и т.д.) Пример использования одно- и многомерных массивов:

// Декларирование одно- и многомерного массива
char text[3];
int table[10][10];
 
// Создание текста из массива знаков
text[0] = 'H';  // Буква
text[1] = 'i';  // Буква
text[2] = 0;    // Признак окончания текста (нулевой байт)
 
// Изменение одного элемента таблицы
table[4][3] = 1;

 

Выражения

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

Арифметические операции

Язык Си поддерживает следующие арифметические операции: сложение (+), вычитание (-), умножение (*), деление (/) и возведение в модуль (%). Примеры использования арифметических операций:

int x, y;
 
// Возведение в модуль, умножение и присвоение значения
// x получает значение 9
x = (13 % 5) * 3;
 
// Оператор присваивания сложения
// x получает значение 14
x += 5;
 
// Суффиксный декремент
// x получает значение 13
x--;

Логические операторы

Логические операторы: логическое отрицание NOT (!), логическое И (&&) и логическое ИЛИ (||). Примеры использования:

bool a, b, c;
 
// Инициация
a = true;
b = false;
 
// Отрицание
// c получит значение false, потому что а имеет значение true
c = !a;
 
// Логическое И
// c получит значение false, так как один из операндов неверный
c = a && b;
 
// Логическое ИЛИ
// c получит значение true, так как один из операндов верный
c = a || b;

NB! Тип данных bool происходит из языка Си++ и в языке Си он отсутствует потому, что вместо него используются целые числа, где 0 имеет значение false и любое другое число значение true. Но для удобства в библиотеке Домашней Лаборатории используется всё же boolи определяется как unsigned char. Константа true имеет значение 1 и false значение 0.

Операторы сравнения

Для сравнения числовых значений получают логические значения. Операторами сравнения являются: равенство (==), неравенство (!=), больше (>), больше или равно (>=), меньше (<) и меньше или равно (⇐). Примеры использования:

int x = 10, y = 1;
 
// Больше, чем оператор сравнения, что true
// Скобки вокруг оператора только для ясности
bool b = (5 > 4);
 
// Неравенство
// Результат false
b = (4 != 4);
 
// Арифметический, логический операторы и оператор сравнения
// b получится false, так как операнд первого логического И неверный
b = (x + 4 > 15) && (y < 4);

Побитовые операторы

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

// Декларирование 8 битной переменной без знака типа char
// Значение переменной в десятичной системе – 5, в двоичной системе - 101
unsigned char c = 5;
 
// Переменная с с оператором ИЛИ и числом 2 (в двоичной системе 010)
// c получит значение 7 (в двоичной системе 111)
c = c | 2;
 
// Побитовый сдвиг влево на 2
// c получит значение 28 (в двоичной системе 11100)
c = c << 2;

Побитовые операции крайне необходимы при использовании регистров микроконтроллеров. Подробнее о них расскажет глава регистров AVR.

 

Функции

Функция – это отрезок программы, который можно вызвать по имени. У функции могут быть параметры, и она может вернуть одно значение. Если функция не возвращает значение, её тип - void. Если у функции нет параметра, следует при использовании старого компилятора языка Си, прописать void вместо декларации параметров. Пример функции сложения и функции без возвращения:

// Декларация функции с двумя параметрами типа int
// Функция возвращает значение типа int
int sum(int a, int b)
{
	// Сложение двух чисел и возвращение суммы
	return a + b;
}
 
// Функция без параметров и возвращаемого значения
void power_off(void)
{
}

Для использования функции следует её вызвать. В программном коде функция должна быть задекларирована до места вызова. Пример вызова функции сложения:

int x;
int y = 3;
 
// Вызов функции сложения
// Параметрами является переменная и значение константы
x = sum(y, 5);
 
// Вызов функции отключения
// Параметры отсутствуют
power_off();

Заполнение программы языка Си начинают с функции main, что делает её обязательной функцией.

 

Выражения

Условные операторы «if» и «else»

Условный оператор, при помощи верного выражения в скобках, позволяет выполнить или не выполнить выражение или отрезок программы, следующие за условием. Ключевым словом условного оператора является if. Пример использования:

// Выражение верное и оператор будет выполнен,
// так как 2 + 1 больше, чем 2
if ((2 + 1) > 2) x = 5;
 
// Если x равен 5 и y 3, то выполняется следующий отрезок программы
if ((x == 5) && (y == 3))
{
	// Случайное действие
	y = 4;
	my_function();
}

Условный оператор может быть длиннее и содержать выражение или отрезок программы, которые выполняются в случае неверности выражения. Для этого требуется использовать ключевое слово else после условного оператора if.

// Х равен 5?
if (x == 5)
{
	// Случайное действие
	z = 3;
}
// Если x не был равен 5, равен ли тогда x 6?
else if (x == 6)
{
	// Случайное действие
	q = 3;
}
// Если х не был равен 5 и 6...
else
{
	// Случайное действие
	y = 0;
}

 

Оператор ветвления

Если выражение требует сравнения с несколькими различными значениями, то используется оператор ветвления с ключевым словом switch. Пример использования:

int y;
 
// Оператор ветвления для сравнения y
switch (y)
{
	// y равен 1?
	case 1:
		// Случайное действие
		function1();
		break;
 
	// y равен 2?
	case 2:
		// Случайное действие
		function2();
		break;
 
	// Все другие случаи
	default:
		// Случайное действие
		functionX();
		// выражение break не требуется,
		// так как сравнение заканчивается
}

Оператор цикла

При помощи данного оператора программный отрезок можно выполнять несколько раз.

while

Это оператор цикла, повторяющий одно и то же действие, пока условие продолжения цикла остаётся истинным.

int x = 0;
 
// Цикл длится до тех пор, пока x меньше чем 5
while (x < 5)
{
	// Прибавление единицы к x
	x++;
}

 

for

Цикл с ключевым словом for схож с циклом while, но отличается тем, что в скобках приведены выражения, выполняемые до и во время каждого цикла.

Пример:

int i, x = 0;
 
// Вначале i объявляется нулём. Цикл выполняется до тех пор, пока 
// i меньше, чем 5. В конце каждого цикла i увеличивается на единицу
for (i = 0; i < 5; i++)
{
	// увеличение x на 2 единицы
	x += 2;
}
 
// Здесь значением x будет 10

Движения в цикле

Циклы while и for можно прервать оператором break. Оператор continue начинает следующий цикл без выполнения последующего кода. Например:

int x = 0, y = 0;
 
// Бесконечный цикл, так как 1 является логической истиной
while (1)
{    
	// Из цикла выходят, если x приобретает значение 100
	if (x >= 100) break;
 
	// увеличение x, чтобы цикл когда-нибудь закончился
	x++;
 
	// Если x равен 10 или меньше, тогда начинается следующий цикл
	if (x <= 10) continue;
 
	// увеличение y
	y++;
}
 
// Здесь значение y 90

Обработка текста

Функции обработки текста в микроконтроллерах нужны, прежде всего, для отображения текста на экране LCD и его передачи/принятия посредством коммуникационного интерфейса.

Функция sprintf

Функция sprintf идентична распространенной в языке Си функции printf. Различием является то, что вывод производится в массив, указанный аргументом buffer, а не в стандартный выход (в микроконтроллерах это обычно последовательный интерфейс). У функции имеется меняющееся количество аргументов, которые форматируются в соответствии с форматом.

Пример 1:

#include <stdio.h>
 
char buffer[20];
int a = 1, b = 2;
int len = sprintf(buffer, "%d плюс %d равно %d", a, b, a + b);
 
// Результатом являются текстовые строки "1 плюс 2 равно 3"

Например, функция sprintf прописывает текст в массив buffer, который составлен из трёх аргументов и форматируется в соответствии с текстовой строкой формата. В текстовой строке формата маркер (англ. specifier) обозначает %d аргумента типа целых чисел, которые следует заменить в тексте. В конец составленного текста автоматически добавляется нулевой байт, который обозначает окончание текстовой строки. Пользователь должен обеспечить, чтобы длинна составляемого текста и нулевого байта не превышала длину массива. Функция sprintf облегчает составление фраз и предложений из переменных разного типа. Функция возвращает длину текста, сохранённого в массиве (длина не содержит нулевой байт). В случае ошибки возвращается отрицательное число.

Пример 2:

#include <stdio.h>
 
char x[20];
sprintf(x, "%s on %d aastat vana", "Juku", 10);
 
// Тот же результат можно достигнуть и:
char x[] = "Juku on 10 aastat vana";

Во втором примере в формате текстовой строки маркер %s заменяется первым аргументом текстового типа и маркер %d – вторым аргументом типа целого числа. Количество маркеров должно совпадать с числом аргументов и их типы должны сочетаться. Так же аргументы должны быть представлены в том же порядке, что и маркеры. Для аргументов различного типа существуют маркеры соответствующего формата:

Маркер Описание Пример
%c Char 'a'
%i или %d Integer 123
%f Real number 3.14f
%s Text “пример”
%X Hexadecimal number 0x3F

Утилиты общего назначения

В библиотеке стандартных функций stdio.h, stdlib.h и string.h имеются различные функции для проведений разных текстовых операций. Например, с их помощью можно преобразовывать текст в числа, соединять тексты и сравнивать их и многое другое.

Случайная функция

Генерирование случайных чисел нелегко для микроконтроллера AVR. Сначала следует ввести число в генератор случайных чисел, на основании которого будет сгенерирован массив случайных чисел. Массив, основанный на одном номере, всегда одинаковый. Чтобы получить более случайный результат, функция может быть введена из значения, взятого из разъединенного АЦП.

Пример генерирования случайного числа в промежутке от 1 до 16 (включительно).

#include <stdlib.h>
 
srand(100); // Случайное число
int x = 1 + (rand() % 16);

Более подробное описание функций языка программирования Си на английском языке можно найти по адресу:http://www.cplusplus.com/reference/clibrary/

~~DISCUSSION~~

ru/programming/c/crashcourse.txt · Last modified: 2020/07/20 09:00 by 127.0.0.1
CC Attribution-Share Alike 4.0 International
www.chimeric.de Valid CSS Driven by DokuWiki do yourself a favour and use a real browser - get firefox!! Recent changes RSS feed Valid XHTML 1.0