====== Curso básico de C ======
===== Estrutura de um programa =====
Um programa na linguagem C pode apresentar as mais diversas formas, até mesmo ser composto por uma única linha, pois o compilador de código atenta apenas ao cumprimento das regras de sintaxe e não exige a implementação de uma estrutura específica. Contudo, é aconselhável aos programadores, adotarem um estilo de programação que apresente clareza e simplicidade para qualquer tipo de pessoa que leia o código. Esta é a estrutura típica de um programa em linguagem C:
/* Include header files */
#include
#include
/* Macro declarations */
#define PI 3.141
/* Data type definitions */
typedef struct
{
int a, b;
}
element;
/* Global variables */
element e;
/* Functions */
int main(void)
{
// Local variables
int x;
// Program code
printf("Hello World!\n");
}
===== Comentários =====
Ao programador é dada a liberdade de escrever qualquer tipo de texto num ficheiro de código. Este texto é geralmente utilizado para escrever anotações ou descrição do funcionamento de um excerto de código, neste caso este texto é ignorado pelo compilador. Os comentários podem também ser utilizados para por exemplo excluir temporalmente bocados de código da compilação. Os dois tipos de métodos de comentários em linguagem C são:
// Line comment is on one line.
// Text after two slash signs is considered as comment.
/*
Block comment can be used to include more than one line.
The beginning and the end of a comment is assigned with slash and asterisk signs.
*/
===== Dados =====
==== Tipos de dados ====
Os tipos básicos de dados do C:
^ Tipo ^ Valor Minimo ^ Valor Máximo ^ Bits ^ Bytes ^
| (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 |
A palavra "signed" em parêntesis é considerada opcional, pois por omissão um qualquer tipo de dados numérico é considerado "signed" (bipolar).
Ns microcontroladores AVR //int// = //short// \\
No PC //int// = //long// \\
A linguagem C não tem um tipo de dados que represente uma string (conjunto de carateres). Em vez disso são utilizados vetores de carateres (assunto que será abordado adiante), e são utilizados carateres ASCII onde a cada caracter alfabético é representado um valor numérico.
==== Variáveis ====
Um programa pode utilizar um tipo de espações de memória pré-definidos, a isto chamamos variáveis. Os nomes das variáveis podem incluir qualquer caratere do alfabeto latino, números ou //underscores//, desde que o primeiro caractere não seja um caractere numérico. Quando se declara uma variável num programa, é necessário preceder o nome da variável com o tipo de dados desejado. Por forma a atribuir-se um valor a uma variável é utilizado o sinal de igualdade (=). A seguir apresenta-se um exemplo que ilustra a utilização de variáveis:
// char type variable c declaration
char c;
// Value is given to variable c.
c = 65;
c = 'A'; // A has in ASCII character map also value 65
// int type variable i20 declaration and initialization
int i20 = 55;
// Declaration of several unsigned short type variables
unsigned short x, y, test_variable;
==== Constantes ====
As constantes são declaradas da mesma maneira que as variáveis, apenas precedendo a palavra //const// com o tipo de dados respetivo. Uma constante nunca altera o seu valor durante a execução de um programa.
Um exemplo de utilização de constantes:
// int type constant declaration
const int x_factor = 100;
==== Estruturas ====
Os tipos básicos de dados podem ser re-agrupados em estruturas por forma a criarem-se tipos de dados mais complexos, recorrendo à palavra //struct//. Uma estrutura representa um tipo de dados combinado, este tipo é declarado com a palavra //typedef//.
Um exemplo sobre estruturas, sua criação e utilização de tipos de dados complexos:
// Declaration of a new data type "point"
typedef struct
{
// x and y coordinates and color code
int x, y;
char color;
}
point;
// declaration of a variable as data type of point
point p;
// Assigning values for point variable
p.x = 3;
p.y = 14;
==== Vetores ====
Os tipos básicos de dados podem ser organizados em vetores. Os vetores podem ter várias dimensões (tabelas, cubos, etc.). Seguem-se exemplos da utilização de vetores de uma e duas dimensões respetivamente:
// Declaration of one- and two-dimensional arrays
char text[3];
int table[10][10];
// Creating a string from char array
text[0] = 'H'; // Char
text[1] = 'i'; // Char
text[2] = 0; // Text terminator (0 B)
// Assigning new value for one element.
table[4][3] = 1;
===== Operadores =====
As variáveis, constantes e valores retornados de funções podem ser utilizados na composição de operações. O resultado de uma operação pode ser atribuído a uma variável, pode ser utilizado como parâmetro para outras funções ou como valor em diversas estruturas de controlo.
==== Operadores aritméticos ====
A linguagem C suporta a generalidade dos operadores aritméticos, como a soma (+), subtração (-), multiplicação (*), divisão (/) e o módulo (%). Seguem-se alguns exemplos ilustrativos da utilização destes operadores:
int x, y;
// Modulo, multiplication and assigning value
// x gets value of 9
x = (13 % 5) * 3;
// Adding-assigning operator
// x gets value of 14
x += 5;
// Quick style method for subtracting 1
// x gets value of 13
x--;
==== Operadores lógicos ====
Os operadores lógicos na linguagem C são compostos pela negação NOT (!), multiplicação lógica AND (&&) e a adição lógica (||). Seguem-se exemplos da utilização destes operadores:
bool a, b, c;
// Initialization
a = true;
b = false;
// Negation
// c will get a value of false because a is true
c = !a;
// Logic multiplication
// c will get a value of false because one of the operators is false
c = a && b;
// Logic addition
// c will get a value of true because one of the operators is true
c = a || b;
**NOTA!** O tipo de dados //bool// na linguagem C, na realidade não existe, pelo que em alternativa geralmente são utilizados valores inteiros para a representação destes valores, em que o valor 0 representa //Falso//, e qualquer outro valor diferente de 0 representa //Verdadeiro//. Por exemplo, na biblioteca do HomeLab, o tipo de dados //bool// é representado pelo tipo de dados //unsigned char//. A constante //Verdadeiro// é então representada pelo valor 1 e //Falso// representado pelo valor 0.
==== Operadores relacionais e de igualdade ====
Os valores lógicos são geralmente resultado de uma comparação entre variáveis. Os operadores de igualdade são: (==) //igual a//, (!=) //diferente//, (>) //maior que//, (>=) //maior ou igual que//, (<) //menor que//, (<=) //menor ou igual que//. Segue-se um exemplo de utilização destes operadores:
int x = 10, y = 1;
// greater than operation which is true
// brackets around the operation are only for clarity
bool b = (5 > 4);
// Not equal to operation
// The result is false
b = (4 != 4);
// Arithmetic, equality and logic operations altogether
// b is false because the first operator of logic multiplication is false
b = (x + 4 > 15) && (y < 4);
==== Operações de bit ====
As operações de //bit// são utilizadas para manipulação de dados em formato binário. Estas apenas podem ser aplicadas a tipos de dados inteiros. As operações de //bit// são bastante semelhantes às operações lógicas, com a única diferença que porque estas são aplicadas diretamente a cada um dos bits que compõem o valor, e não apenas ao conjunto que compõem o número. As operações de //bit// que existem na Linguagem C são a inversão (~), conjunção (&), disjunção (|), anti-valência (^), rotação à esquerda (<<) e a rotação à direita (>>).
// Declaration of unsigned 8 bit char type variable
// Variable value is 5 in decimal system, 101 in binary system
unsigned char c = 5;
// Disjunction of c with a digit 2 (010 in binary)
// c value will become 7 (111 in binary)
c = c | 2;
// Bit left shift by 2
// c value will become 28 (11100 in binary)
c = c << 2;
As operações de //bit// são essenciais na manipulação de registos de um microcontrolador. Estes registos serão descritos adiante no capítulo de registos do AVR.
===== Funções =====
As funções definem partes de um programa que pode ser denominadas e invocadas pelo nome. As funções podem incluir parâmetros de entrada e permitem retornar um valor de saída. Se a função não retorna nenhum valor, esta função é definida com o tipo //void//. Se a função não possui parâmetros de entrada, em versões mais antigas da Linguagem C, o tipo //void// também deve ser incluído dentro dos parêntesis da sua declaração.
Segue-se um exemplo de uma função que adiciona dois números inteiros e outro de uma função que não retorna nenhum valor.
// Declaration of 2 int type parameter function
// The function returns int type value
int sum(int a, int b)
{
// Addition of 2 variables and returning of their sum
return a + b;
}
// Function without parameters and no return output
void power_off(void)
{
}
Para utilizar-se uma função, esta deve ser invocada. Para isso, é necessário que a função seja declarada antes de ser invocada. Um exemplo com a invocação de uma função:
int x;
int y = 3;
// Calling an addition function
// Parameetriteks on muutuja ja konstandi väärtus
// The parameters are variable and constant
x = sum(y, 5);
// The call of a power off function
// No parameters
power_off();
A execução de um programa em Linguagem C é sempre iniciada na função //main//.
===== Declarações =====
==== Declarações If/Else ====
As declarações condicionais, permitem a execução condicional do código de um programa com base em operações lógicas e/ou relacionais. Uma declaração condicional utiliza a palavra //if//. Exemplo:
// Statement is true and operation x = 5 will be executed
// because 2 + 1 is higher than 2
if ((2 + 1) > 2) x = 5;
// If x equals 5 and y equals 3 then the following code will be executed
if ((x == 5) && (y == 3))
{
// Random action
y = 4;
my_function();
}
Um //if// permite também adicionar uma cláusula //else// que só é executada em caso do valor Falso. Exemplo:
// Is x equal with 5 ?
if (x == 5)
{
// Random action
z = 3;
}
// If this is false then x might be equal with 6
else if (x == 6)
{
// Random action
q = 3;
}
// If x was not 5 nor 6 ...
else
{
// Random action
y = 0;
}
==== Declaração Switch ====
Quando é necessário comparar operações e variáveis com várias combinações de diferentes valores, é geralmente recomendável que se use em alternativa uma comparação com base na declaração //switch//. Exemplo da sua utilização:
int y;
// Switch statement for comparing y
switch (y)
{
// is y equal to 1 ?
case 1:
// Random action
function1();
break;
// is y equal to 2 ?
case 2:
// Random action
function2();
break;
// All other cases
default:
// Random action
functionX();
// break operation not needed,
// because the comparison ends anyway
}
===== Loops =====
Os //loops// permitem-nos executar código várias vezes.
==== while loop ====
O código encapsulado por um //while// é executado até que a condição entre parêntesis obtenha o valor Falso. Exemplo:
int x = 0;
// Loop will execute until x is smaller than 5
while (x < 5)
{
// x incrementation
x++;
}
==== for loop ====
O loop //for// assemelha-se ao loop //while//, excepto que as operações que este engloba são executadas antes da condição de e a verificação da condição é sempre efetuada no fim de cada ciclo. Exemplo:
int i, x = 0;
// i is equal to 1 at the beginning of the loop.
// Loop will be executed until i is smaller than 5.
// i will be incremented in the end of every loop cycle.
for (i = 0; i < 5; i++)
{
// x addition by 2
x += 2;
}
// here x value is 10
==== Saída de loops ====
A iteração de ciclos //while// ou //for// pode ser terminada com a instrução //break//. Para retomar a próxima iteração de um ciclo evitanto a execução do código que se segue pode ser feita com um //continue//. Por exemplo:
int x = 0, y = 0;
// Infinite loop because 1 is logic true
while (1)
{
// Exit the the loop cycle if x becomes 100
if (x >= 100) break;
// x incrementation to end loop at some time
x++;
// If x is 10 or less then the next cycle is started
if (x <= 10) continue;
// y incrementation
y++;
}
// Here y value is 90
==== Operações de texto ====
As operações de texto são geralmente utilizadas em microcontroladores para mostrar caracteres e texto num ecrã LCD, por exemplo.
==== sprintf ====
A função //sprintf// é bastante simular à função //printf// mais comumente utilizada na Linguagem C. A diferença entre estas é que o resultado desta função é carregado numa variável em vez do //standard output//.
return = sprintf(variable, parameter_text, parameters);
Exemplo:
int r = sprintf(buffer, "%d pluss %d on %d", a, b, a+b);
Esta função carrega a variável passada como primeiro argumento com texto formatado, texto este que é passado como segundo argumento da função, ao qual podem ser atribuídos valores com os seus restantes argumentos. O uso da função //sprintf// permitirá compôr texto mais complexo de maneira mais simples. Como retorno, esta função devolve o tamanho do texto que foi carregado na variável e no caso de erro, um valor negativo é retornado.
Exemplo:
sprintf(x, "%d. is first", 1);
// the same result can be achieved also:
x = "1. is first";
sprintf(x, "%s is %d years old", "Juku", 10);
// the same result can be achieved also:
x = "Juku is 10 years old";
%s e %d neste exemplosão parâmetros que irão ser substituídos pelos valores dos dois últimos parâmetros da função, respetivamente. O número de parâmetros deve igualar ao número de variáveis utilizadas na expressão.
No primeiro exemplo, o parâmetro %d toma o valor 1. No segundo exemplo, os parâmetros %s e %d são substituídos pelos valores das variáveis, "Juku" e 10 respetivamente. Esta ordem de substituição dos parâmetros é respetiva à ordem em que se apresentam os valores. Existem vários descrições para os diferentes tipos de dados:
^ Parameter ^ Description ^ Example ^
| %c | Char | a |
| %i or %d | Integer| 123 |
| %f | Real number | 3,14 |
| %s | Text | example|
| %X | Hexadecimal number| 3F |
#include
int main ()
{
char buffer [50];
int n, a=5, b=3;
n=sprintf (buffer, "%d plus %d is %d", a, b, a+b);
printf ("\"%s\" is %d digits long\n",buffer,n);
return 0;
}
==== Funções genéricas ====
A biblioteca standard da Linguagem C (stdlib.h) inclui funções que permitem a simplificação de várias operações e conversões mais comuns
==== Função aleatória ====
Não é fácil gerar um número aleatório num microcontrolador.
Primeiro, é necessário dar como parâmetro de entrada um //gerador// que servirá como base para a geração do conjunto de números aleatórios. Este conjunto, se for sempre baseado no mesmo número //gerador//, será sempre igual. Por forma a tornar o resultado desta função mais aleatório, geralmente utiliza-se como valor //gerador//, um dos valores recolhidos de um dos pinos do ADC do microcontrolador.
Exemplo:
srand(100);
rand();
Exemplo de geração de um número aleatório na gama de 1-16:
#include
int x;
x=rand() % 16;
Para uma descrição mais detalhada de todas as funções incluídas na Linguagem C:
[[http://www.cplusplus.com/reference/clibrary/|http://www.cplusplus.com/reference/clibrary/]]