drac0Sha писал(а):Ребят, помогите, пожалуйста разобраться с USARTOM.
у меня такое задание:
Разработать программу, реализующую генератор изменяемой частоты. Начальная частота – 0.5 Гц, т.е. желтый индикатор 1 с горит, 1 с не горит и т.д. Нажатие кнопки 1 приводит к увеличению частоты на 40%, нажатие кнопки 2 уменьшает частоту на 40%. Для облегчения замера частот использовать красный и зеленый индикаторы: красный должен мигать с частотой в 10 раз большей основной частоты (желтого индикатора), а зеленый должен мигать с частотой в 10 раз меньше основной. Одновременное нажатие обеих кнопок должно возвращать генератор в исходное состояние – 0.5 Гц.
Должны обеспечиваться следующие форматы сообщений как от ПК к узлу, так и от узла к ПК:
SOF len message CS
SOF – Start of Frame, признак начала сообщения, 1 байт, 0x7E;
len – длина сообщения в байтах, 1 байт;
message – сообщение, len байт;
CS – контрольная сумма, 1 байт
Контрольная сумма CS должна вычисляться сложением байтов поля message при помощи операции «ИСКЛЮЧАЮЩЕЕ ИЛИ».
При передаче 8-битных байтов использовать проверку четности и 1 стоповый бит. Постараться организовать взаимодействие на максимально возможной скорости.
Что нужно сделать
o Запрос состояния (query). В ответ на этот запрос узел должен сообщить номер своего состояния, оставшееся время нахождения в нем (в единицах таймера) и состояние индикаторов.
o Установка состояния (set). Узел должен немедленно установить запрошенное состояние и оповестить ПК об успешном выполнении команды.
o Еще 2-3 команды по усмотрению.
Вот код:Спойлер
Код: Выделить всё
#define F_CPU 8000000UL // указываем частоту в герцах
#include <stdlib.h>
#include <avr/io.h> // регистры ввода/вывода
#include <avr/interrupt.h> // обработка прерываний
#include <avr/delay.h> //задержка
unsigned int next_frequency = 0; // признак смены частоты
unsigned int current_message = 0; // текущее сообщение
unsigned int length_of_get_message = 0; // длина полчаемого сообщения
unsigned int data_message[100]; // получаемое сообщение
unsigned int control_summ; // контрольная сумма
volatile unsigned int Step; // общий шаг частоты
volatile unsigned int Step_inc; //шаг увеличения частоты
volatile unsigned int Step_dec; //шаг уменьшения частоты
volatile unsigned int Count_time_seconds; // счетчик для мигания зеленого
volatile unsigned int button; // признак нажатия кнопки
volatile unsigned int Frequency; // время таймера
volatile unsigned int Frequency_yellow; // частота желтого
volatile unsigned int Count_time_seconds_red; //счетчик для мигания красного
volatile unsigned int Frequency_yellow_temp;
#define Size_of_queue 150
#define SOF 0x7E
unsigned char Queue[Size_of_queue]; //очередь запросов
unsigned char* first_byte = Queue; //первый запрос в очереди
unsigned char* last_byte = Queue; //последний запрос в очереди
unsigned char queue_is_free = 1; //очередь пуста
//==================
//==================
/// запросы
enum Types_of_inquiry
{
Get_status = 0x31, //получить статус
Set_status = 0x32, // установить статус
Decrease_status = 0x33, // уменьшаем частоту
Increase_status = 0x34, // увеличиваем частоту
Reset_control = 0x35, // перезапуск
Control_was_restarted = 0x10, //факт рестарта
Frequency_decrease = 0x11, // переход на уменьшение частоты
Frequency_increase = 0x12, // переход на увеличение частоты
Status_was_getting = 0x13, // статус был получен
Status_was_setting = 0x14, // статус был установлен
UNDEFINED_COMMAND = 0x20, // неизвестная команда
Next_step_by_timer = 0x16, // переход на след частоту по таймеру
Button_was_pressed= 0x17, //нажали кнопку
Control_summ_is_bad = 0x18 // неверная контрольная сумма
};
//==================
// добавление байта в очередь
void Add_byte_to_queue(unsigned char byte)
{
if (last_byte != first_byte || queue_is_free == 1){
*last_byte = byte;
last_byte++;
if (last_byte == Queue + Size_of_queue){
last_byte = Queue;
}
queue_is_free = 0;
}
}
//==================
// получение байта из очереди
unsigned char Get_byte_from_queue()
{
unsigned char byte = *first_byte;
first_byte++;
if (first_byte == Queue + Size_of_queue){
first_byte = Queue;
}
if (first_byte == last_byte){
queue_is_free = 1;
}
return byte;
}
//==================
// отсылка байта через USART
void USART1_send_byte(unsigned char message)
{
//Ждем пока данные передаются
while ( !(UCSR1A & (1<<UDRE1)) );
UDR1 = message;
}
//==================
// отсылка сообщения через USART
void USART1_send_message (unsigned char *message, unsigned char length)
{
// посылаем признак начала сообщения
USART1_send_byte(SOF);
// длина сообщения
USART1_send_byte(length);
unsigned char control_Summ = 0;
// посылаем сообщение
for(unsigned char i = 0; i < length; i++)
{
USART1_send_byte(message[i]);
control_Summ ^= message[i];
}
// контрольная сумма
USART1_send_byte(control_Summ);
}
//==================
/*Функция уменьшения частоты */
void DecreaseFrequency()
{
if (Frequency_yellow < (65535/1.4)) {
Frequency_yellow = Frequency_yellow*1.4;
}
}
//==================
/* Функция увеличения частоту */
void IncreasedFrequency()
{
if (Frequency_yellow > 1) {
Frequency_yellow =Frequency_yellow*0.6;
}
}
//==================
// ФУНКЦИЯ 3 установить состояние
void Set_status_function (unsigned int *data){
// номер шага, соответственно, частота
PORTB = data[1];
PORTE = data[2];
// поличуть текущее время на единичном интервале
TCNT1 = data[3];
TCNT1 = data[4]>>8;
}
//==================
// ФУНКЦИЯ 4 restart
void Restart_Controller()
{
Frequency_yellow = 0.1*8000000/64;
}
//==================
// полное состояние контроллера
void Full_Status_Controller (unsigned int *data, unsigned int length,unsigned char _SOF )
{
// тип сообщени
data[0] = _SOF;
// номер шага, соответственно, частота
data[1] = PORTB;
data[2] = PORTE;
// текущее время на данном шаге в единицах таймера
data[3] = TCNT1>>8;
data[4] = TCNT1;
length = 5;
}
//==================
// передача полного сообщения
void Send_Status(unsigned char _SOF)
{
unsigned char length = 10;
unsigned char data[100];
Full_Status_Controller(data, length,_SOF);
USART1_send_message(data, length);
}
//==================
// разбор USART сообщегия
void USART_work (unsigned int *data){
switch (data[0]){
case Get_status: // если поличуть статус
Send_Status (Status_was_getting); // сообщили
break;
case Set_status: // установить статус
Set_status_function(data); // выполнить нужное действие
Send_Status (Status_was_setting); // сообщить об этом
break;
case Decrease_status:
DecreaseFrequency ();
Send_Status (Frequency_decrease);
break;
case Increase_status:
IncreasedFrequency();
Send_Status (Frequency_increase);
break;
case Reset_control:
Restart_Controller();
Send_Status (Control_was_restarted);
break;
default: // ошибка
Send_Status (UNDEFINED_COMMAND);
break;
}
}
//==================
// обработка комманды в очереди
void Work_command(){
unsigned char answer_message[2]; // отправляемое сообщение об ошибке
while (!queue_is_free){
unsigned char byte = Get_byte_from_queue(); // взяли байт из очереди
switch (current_message){
case 0: // начинается сообщение
if (byte == SOF){ // если первое это признак начала
data_message[current_message] = byte; // взяли его
current_message++; // след шаг
}
else{
answer_message[0] = UNDEFINED_COMMAND;//если не признак начала - ошибка
answer_message[1] = byte;
USART1_send_message(answer_message, 2); // сообщили
}
break;
case 1: // если уже послали признак начала сообщения
data_message[current_message] = byte;// формируем сообщение
current_message++; // след шаг
length_of_get_message = byte; // взяли длинку, тк это следующрий элемент
control_summ = 0;
break;
default: // идет сам текст сообщения
data_message[current_message] = byte; // взяли элемент
current_message++; // слудующий
if (length_of_get_message > 0){ // на каждом шаге считаем контрольную сумму
length_of_get_message--; // ум длину
control_summ ^= byte; // собственно, контрольная сумма
}else{ // когда дошли до конца сообщения
if (control_summ == byte){ // если реальная сумма равно теоретической
USART_work(data_message); // передать на USART
}else{ // если контрольная сумма не совпадает
data_message[0] = Control_summ_is_bad; // ошибка
USART1_send_message(data_message, data_message[1]);
}
current_message = 0;
}
break;
}
}
}
//==================
//==================
// инициализация
//==================
//==================
void Ititual(){
// красная лампочка
DDRE = (1<<PE1)|(1<<PE2)|(1<<PE3);
PORTE = (1<<PE1)|(1<<PE2)|(1<<PE3);
// кнопка
DDRB = (0<<PB5)|(0<<PB6);
PORTB = (1<<PB5)|(1<<PB6);
// предделитель наймера 64
TCCR1B = (0<<CS12)|(1<<CS11)|(1<<CS10);
// разрешаем прерывание от таймера 1.
TIMSK = (1<<TOIE1);
TCNT1 = 65536 - 0.1*8000000/64;
Frequency_yellow = 0.1*8000000/64;
sei();
//задаем скорость обмена, устанавливаем USART в нужный режим работы
UBRR1H = 0;
UBRR1L = 51;
//разрешаем прием-передачу
UCSR1B = (1<<RXEN1)|(1<<TXEN1)|(1<<RXCIE1)|(0<<TXCIE1);
//устанавливаем асинхронный режим работы и формат посылки: 8 бит, 1 стопповый бит
UCSR1C = (0<<USBS1)|(1<<UCSZ10)|(1<<UCSZ11)|(0<<UCSZ12)|(0 << UMSEL1)|(0<<UPM10)|(0<<UPM11);
}
//==================
SIGNAL(SIG_OVERFLOW1){
TCNT1 = 65536 - Frequency_yellow ;
PORTE = PINE^(1<<PE3);
if (Count_time_seconds == 10) {
PORTE = PINE^(1<<PE2);
Count_time_seconds = 0;
Count_time_seconds_red++;
if (Count_time_seconds_red == 10) {
PORTE = PINE^(1<<PE1);
Count_time_seconds_red=0;
}
}
Count_time_seconds++;
//==================
}
// прерывание при получении данных по USART
SIGNAL (SIG_USART1_RECV)
{
Add_byte_to_queue(UDR1);
}
//==================
//==================
// главная программа
int main()
{
Ititual(); // инициализация
while (1){ // бесконечный цикл
_delay_ms(500); // формируем задержку 0.5с
/*проверяем одновременное нажатие двух кнопок */
if ((PINB & (1<<PB6 | 1<<PB5))==0) {
Frequency_yellow = 0.1*8000000/64;
}
else{
/* если обе кнопки не нажаты, то перейдем к проверке нажатия одной из кнопок*/
// проверяем нажатие кнопки уменьшения частоты
if ((PINB & (1<<PB6)) == 0){ // проверяем нажатие кнопки
if (Frequency_yellow < (65535/1.4)) {
Frequency_yellow = Frequency_yellow*1.4;
}
}
// проверяем нажатие кнопки увеличения частоты
if ((PINB & (1<<PB5)) == 0){ // проверяем нажатие кнопки
if (Frequency_yellow > 1) {
Frequency_yellow =Frequency_yellow*0.6;
}
}
}
Work_command();
}
return 0;
}
//==================
//==================
Тестирую в протеусе : подключил к собранной схеме virtual terminal. Нажимаю на кнопку 3 ( ASCII код 33) - должна поидее уменьшится частота, но мне в ответ приходит такое сообщение :
7E 02 20 33 13 и частота не уменьшается..
7E - начало сообщения (правильно), дальше должна идти длина сообщения (1 байт), тут почему то выдает 02, далее само сообщение (20 - неизвестная команда) , 33 код кнопки (ASCII) и 13 - контрольная сумма.
Подскажите, пожалуйста, может я не так ввожу команду или что-то неправильно в коде ?
1. протеус г.. я на нем несколько раз крепко прокалывался, отрабатывать необходимо каждую функцию по отдельности например в авр студ(неудобно но работает правильно) а лучше на железе.
2. буфер для USARTA сила, минимум в два раза больше максимальной длины посылки.
3. используйте таблицы а не формулы где это возможно.
4. критические части кода пишите на ассемблере.
5. пишите более читабельный и "прямой код" если хотите чтоб его читали(у Вас код читабельный, общая рекомендация).
6. кварц лучше использовать USARTовский.