1. протеус г.. я на нем несколько раз крепко прокалывался, отрабатывать необходимо каждую функцию по отдельности например в авр студ(неудобно но работает правильно) а лучше на железе.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 команды по усмотрению.
Вот код:Тестирую в протеусе : подключил к собранной схеме virtual terminal. Нажимаю на кнопку 3 ( ASCII код 33) - должна поидее уменьшится частота, но мне в ответ приходит такое сообщение :Спойлер
Код: Выделить всё
#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; } //================== //==================
7E 02 20 33 13 и частота не уменьшается..
7E - начало сообщения (правильно), дальше должна идти длина сообщения (1 байт), тут почему то выдает 02, далее само сообщение (20 - неизвестная команда) , 33 код кнопки (ASCII) и 13 - контрольная сумма.
Подскажите, пожалуйста, может я не так ввожу команду или что-то неправильно в коде ?
2. буфер для USARTA сила, минимум в два раза больше максимальной длины посылки.
3. используйте таблицы а не формулы где это возможно.
4. критические части кода пишите на ассемблере.
5. пишите более читабельный и "прямой код" если хотите чтоб его читали(у Вас код читабельный, общая рекомендация).
6. кварц лучше использовать USARTовский.


