Страница 32 из 111
Re: WinAvr в вопросах и ответах
Добавлено: Чт ноя 25, 2010 12:13:37
PILS1396
ARV писал(а):PILS1396 писал(а):Извиняюсь, ошибся темой пишу в cvavr. Но в прерывании (при переполнении буфера приема) каждый байт записывается в массиве rx_buffer [], а нумерации начинается с нуля.
То есть как я понимаю переданы 150 записываются в массиве как:
rx_buffer [0] = 1
rx_buffer [1] = 5
rx_buffer [2] = 0
так вот хренушки! если вы послали "150" из терминальной программы, то у вас будет
rx_buffer [0] = '1'
rx_buffer [1] = '5'
rx_buffer [2] = '0'
а это совершенно не то!
с другой стороны, я не знаю, что у вас за терминалка, но ежели она вдруг посылает именно ЧИСЛО 150, то у вас будет еще лучше:
rx_buffer [0] = 150
rx_buffer [1] = неизвестно что
rx_buffer [2] = неизвестно что
собственно, о чем я и писал: вы не знаете Си и своих собственных инструментов. бегом читать букварь!

Спасибо иду читать букварь
Re: WinAvr в вопросах и ответах
Добавлено: Чт ноя 25, 2010 12:27:28
PILS1396
AlexFisher писал(а):Ошибок может быть по крайней мере 2:
1. Группа операторов начнет работать, когда передан всего один символ из трех (то есть уже не правильно)
2. Группа операторов не вычищает за собой вышеозначенный буфер, то есть не заносит туда 0х00
Это я учел. Но при передаче сообщения "150" прерывание происходило, а при передаче сообщения "1" не происходит, а происходит при передаче еще двух аналогичных сообщений.
Re: WinAvr в вопросах и ответах
Добавлено: Чт ноя 25, 2010 13:10:13
PILS1396
Разобрался

Re: WinAvr в вопросах и ответах
Добавлено: Чт ноя 25, 2010 14:39:57
alexval2006
есть нужда обозвать порт PORTC как нибудь по другому и по #define его чтобы все порты разом пенять по необходимости а то во многих местах менять приходиться как это сделать правильно а то мои эксперименты нечем хорошим не увенчались компилятор либо ругается либо нечего не работает
// Выводим данные на DataPin (PC0)
PORTC &=~_BV(DataPin); // установим DataPin в "0"
else // иначе
PORTC |=_BV(DataPin); // установим DataPin в "1"
asm("nop"); // задержка в один такт
да еще немного о правилах размещения цикла майн в программе почему он должен быть обязательно в самом низу кода? иначе чущ начинаетса
Re: WinAvr в вопросах и ответах
Добавлено: Чт ноя 25, 2010 15:18:06
ARV
alexval2006 писал(а):есть нужда обозвать порт PORTC как нибудь по другому и по #define его чтобы все порты разом пенять по необходимости а то во многих местах менять приходиться как это сделать правильно а то мои эксперименты нечем хорошим не увенчались компилятор либо ругается либо нечего не работает
// Выводим данные на DataPin (PC0)
PORTC &=~_BV(DataPin); // установим DataPin в "0"
else // иначе
PORTC |=_BV(DataPin); // установим DataPin в "1"
asm("nop"); // задержка в один такт
я не понял, что вам надо и что не так - приведенный код нормальный, рабочий, правильный.
alexval2006 писал(а):да еще немного о правилах размещения цикла майн в программе почему он должен быть обязательно в самом низу кода? иначе чущ начинаетса
и снова не понял: main - это функция, а не цикл. но в ней обычно имеется главный цикл... так снова: что не так? если вы объявили прототипы всех функций, кроме main, то сам main (который не нуждается в объявлении прототипа) может быть в любом месте, не обязательно внизу.
правило си: каждая функция должна быть объявлена или определена ранее, чем использована.
Re: WinAvr в вопросах и ответах
Добавлено: Чт ноя 25, 2010 15:34:16
alexval2006
[quote]правило си: каждая функция должна быть объявлена или определена ранее, чем использована.[quote] ЭТО БЫЛА МОЯ ОШИБКА СПАСИБО
А что касаемо кода то да он правильный дан для примера мне нужно букву порта менять, ну вот нечто такое но почему то не получается
#define PORT@ PORTC //выбран порт PORTC
PORT@ &=~_BV(DataPin); // установим DataPin в "0"
else // иначе
PORT@ |=_BV(DataPin); // установим DataPin в "1"
ДОБАВЛЕНО ПОЗЖЕ
вопрос решен эти две ошибки наслаивались друг на друга и создавали полную кашу
#define PORTX1 PORTD //выбран порт PORTC
// Выводим данные на DataPin (PC0)
PORTX1 &=~_BV(DataPin); // установим DataPin в "0"
else // иначе
PORTX1 |=_BV(DataPin); // установим DataPin в "1"
asm("nop"); // задержка в один такт
так отлично работает
Re: WinAvr в вопросах и ответах
Добавлено: Чт ноя 25, 2010 16:04:53
ARV
как обычно, вопросы задаются так, что приходится гадать - что же именно вызывает проблему?
я вот для себя сделал файлик с удобными макросами, назвал его avr-helper.h и подключаю его ко всем своим проектам. файлик прилагаю. думаю, вам стоит обратить внимание на макрос
CONCAT, я использую его для таких целей:
Код: Выделить всё
#define OUT_ D /* обратите внимание - только БУКВА порта*/
#define OUT_PORT CONCAT(PORT, OUT_)
#define OUT_DDR CONCAT(DDR, OUT_)
#define OUT_PIN CONCAT(PIN, OUT_)
// и далее я использую уже не конкретный PORTD, а эти макросы:
OUT_DDR = 254; // все на вывод, кроме младешего бита
OUT_PORT = 1; // подтяжка на младший бит
if(OUT_PIN & 1) // проверка уровня на младшем пине
то есть в программе я уже нигде не указываю настоящие имена регистров портов PORTC или DDRB, а использую их макросы-алиасы. если вдруг приспичит изменить порт кнопок с порта С на порт В, мне придется поменять только ОДНУ-ЕДИНСТВЕННУЮ букву в ОДНОМ-ЕДИНСТВЕННОМ дефайне - остальная часть программы останется нетронутой
Re: WinAvr в вопросах и ответах
Добавлено: Чт ноя 25, 2010 16:11:36
alexval2006
спасибо поюзаем
обявляютса так?
//Прототипы подпрограмм
void USART_Transmit( unsigned char data );
void USART_Init( unsigned int ubrr);
Re: WinAvr в вопросах и ответах
Добавлено: Чт ноя 25, 2010 16:18:12
ARV
alexval2006 писал(а):спасибо поюзаем

на здоровье. там еще кое-что удобственное имеется, особенно если редактор умеет по мере ввода подсказывать "окончания"... например, надо задать предделитель таймера: начинаем вводить TIMER_CLK_ и редактор подсказывает возможные окончания DIV_1 или DIV_8 или DIV_64 и т.д. - остается только выбрать и нажать ENTER

в принципе, если хорошенько прочесть файлик и уловить логику составления имен макросов, несложно и на память все помнить...
надеюсь, вам понравится.
Re: WinAvr в вопросах и ответах
Добавлено: Чт ноя 25, 2010 16:18:52
ARV
alexval2006 писал(а):обявляютса так?
//Прототипы подпрограмм
void USART_Transmit( unsigned char data );
void USART_Init( unsigned int ubrr);
да
Какой-то бред в Студио 4.18SP3 и GCC
Добавлено: Пт ноя 26, 2010 12:46:48
Reset
Скачал сабж, решил с асма переползти (не знаю зачем, наверное от того, что чаще стали попадаться для доводки до ума коряво писаные проекты на С).
Ну пробую вообще на предмет, что он работает. Пишу:
Код: Выделить всё
#include <avr/io.h>
#include <avr/iom128.h>
#include <avr/interrupt.h>
//******************************************************//
int main (void)
{
int a=4;
PORTB=a;
if(PINB!=0xFF)
{
a=3;
}
while(1)
{
a++;
}
}
В результате компилится вот в этот перл:
Код: Выделить всё
0: File not found
+00000000: 940C0046 JMP 0x00000046 Jump
+00000002: 940C0050 JMP 0x00000050 Jump
+00000004: 940C0050 JMP 0x00000050 Jump
+00000006: 940C0050 JMP 0x00000050 Jump
+00000008: 940C0050 JMP 0x00000050 Jump
+0000000A: 940C0050 JMP 0x00000050 Jump
+0000000C: 940C0050 JMP 0x00000050 Jump
+0000000E: 940C0050 JMP 0x00000050 Jump
+00000010: 940C0050 JMP 0x00000050 Jump
+00000012: 940C0050 JMP 0x00000050 Jump
+00000014: 940C0000 JMP 0x00000000 Jump
+00000016: 940C0050 JMP 0x00000050 Jump
+00000018: 940C0050 JMP 0x00000050 Jump
+0000001A: 940C0050 JMP 0x00000050 Jump
+0000001C: 940C0050 JMP 0x00000050 Jump
+0000001E: 940C0050 JMP 0x00000050 Jump
+00000020: 940C0050 JMP 0x00000050 Jump
+00000022: 940C0050 JMP 0x00000050 Jump
+00000024: 940C0050 JMP 0x00000050 Jump
+00000026: 940C0050 JMP 0x00000050 Jump
+00000028: 940C0050 JMP 0x00000050 Jump
+0000002A: 940C0050 JMP 0x00000050 Jump
+0000002C: 940C0050 JMP 0x00000050 Jump
+0000002E: 940C0050 JMP 0x00000050 Jump
+00000030: 940C0050 JMP 0x00000050 Jump
+00000032: 940C0050 JMP 0x00000050 Jump
+00000034: 940C0050 JMP 0x00000050 Jump
+00000036: 940C0050 JMP 0x00000050 Jump
+00000038: 940C0050 JMP 0x00000050 Jump
+0000003A: 940C0050 JMP 0x00000050 Jump
+0000003C: 940C0050 JMP 0x00000050 Jump
+0000003E: 940C0050 JMP 0x00000050 Jump
+00000040: 940C0050 JMP 0x00000050 Jump
+00000042: 940C0050 JMP 0x00000050 Jump
+00000044: 940C0050 JMP 0x00000050 Jump
+00000046: 2411 CLR R1 Clear Register
+00000047: BE1F OUT 0x3F,R1 Out to I/O location
+00000048: EFCF SER R28 Set Register
+00000049: E1D0 LDI R29,0x10 Load immediate
+0000004A: BFDE OUT 0x3E,R29 Out to I/O location
+0000004B: BFCD OUT 0x3D,R28 Out to I/O location
+0000004C: 940E0052 CALL 0x00000052 Call subroutine
+0000004E: 940C0056 JMP 0x00000056 Jump
+00000050: 940C0000 JMP 0x00000000 Jump
@00000052: main
---- GCC_tst.c ------------------------------------------------------------------------------------
7: {
+00000052: E084 LDI R24,0x04 Load immediate
+00000053: BB88 OUT 0x18,R24 Out to I/O location
10: if(PINB!=0xFF)
+00000054: B386 IN R24,0x16 In from I/O location
+00000055: CFFF RJMP PC-0x0000 Relative jump
10: if(PINB!=0xFF)
+00000056: 94F8 CLI Global Interrupt Disable
+00000057: CFFF RJMP PC-0x0000 Relative jump
+00000058: 00FF ??? Data or unknown opcode
+00000059: FFFF ??? Data or unknown opcode
+0000005A: FFFF ??? Data or unknown opcode
Во первых - висит себе на сишной строчке if(PINB!=0xFF), что соответствует бесконечному циклу по адресу 55
Код: Выделить всё
...
10: if(PINB!=0xFF)
+00000054: B386 IN R24,0x16 In from I/O location
+00000055: CFFF RJMP PC-0x0000 Relative jump
10: if(PINB!=0xFF)
+00000056: 94F8 CLI Global Interrupt Disable
+00000057: CFFF RJMP PC-0x0000 Relative jump
+00000058: 00FF ??? Data or unknown opcode
...
, что собственно и должен делать (ну как ему по rjmp пц-0 не повиснуть-то..
Вопрос логичен до нельзя: - что не так? Варнингов при компиляции нет. таргет - mega128...
Во вторых - руководствуясь ЧЕМ оно main вызывает через CALL? Это как-то можно исправить на нормальный rjmp?
В третьих:
Почему 10: if(PINB!=0xFF) - 2 раза встречается?
Re: WinAvr в вопросах и ответах
Добавлено: Пт ноя 26, 2010 13:12:54
ARV
1. не нужно писать
#include <avr/iom128.h> - если вы настроили проект правильно, нужный модуль микроконтроллера будет подключен автоматически изнутри
#include <avr/iо.h>
2. правильно висит на бесконечном цикле, ничего не делая: вы в своей программе что-то сделали?! ваш цикл
while(1){a++;} не делает ничего, что хоть как-то может повлиять на что-то - вот оптимизатор компилятора и выбросил изменение переменной, как явно бесполезное действие, и остался только бесконечный цикл.
3. по стандарту Си функция
main() - это именно функция, а функции вызываются при помощи
CALL. согласен, это перебор для AVR - но в сущности никакой проблемы не представляет: вам оно не все равно, будет там
JMP или
CALL? лишних пара байт в коде, но ведь работать будет нормально!

4. в листинге из-за работы оптимизатора порой возникают чУдные вещи, например, повторение кусков исходного текста в разных местах листинга. эта проблема известна, но ее не могут побороть (или не хотят) разработчики
avr-gcc. главное, что в коде нет лишних повторов, а листинг, хоть и слегка замусоривается, тем не менее вполне читабельный... смиритесь

Re: WinAvr в вопросах и ответах
Добавлено: Пт ноя 26, 2010 13:20:36
Reset
ARV писал(а):1. не нужно писать
#include <avr/iom128.h> - если вы настроили проект правильно, нужный модуль микроконтроллера будет подключен автоматически изнутри
#include <avr/iо.h>
2. правильно висит на бесконечном цикле, ничего не делая: вы в своей программе что-то сделали?! ваш цикл
while(1){a++;} не делает ничего, что хоть как-то может повлиять на что-то - вот оптимизатор компилятора и выбросил изменение переменной, как явно бесполезное действие, и остался только бесконечный цикл.
3. по стандарту Си функция
main() - это именно функция, а функции вызываются при помощи
CALL. согласен, это перебор для AVR - но в сущности никакой проблемы не представляет: вам оно не все равно, будет там
JMP или
CALL? лишних пара байт в коде, но ведь работать будет нормально!

4. в листинге из-за работы оптимизатора порой возникают чУдные вещи, например, повторение кусков исходного текста в разных местах листинга. эта проблема известна, но ее не могут побороть (или не хотят) разработчики
avr-gcc. главное, что в коде нет лишних повторов, а листинг, хоть и слегка замусоривается, тем не менее вполне читабельный... смиритесь

Всё бы хорошо, но симулятор по этой дряни не ходит нормально.
И что значит "ни чего не делает"? А а++ - это он считает "ничего"м?
Не совать же все переменные волетайлом, чтобы он не трогал... или совать? Вроде как именно изза приколов RS232 старых машин, где для инициализации порта надо было 2 раза писать в один и тот же адрес одно и то же и оптимизатор тупо резал код, и появился волетайл..
А за "не нужно писать include" - бальшой пасиб.
проверил
Добавлено: Пт ноя 26, 2010 13:33:24
Reset
volatile int a - полностью решает проблему. Но тогда без оптимизации код 182 байта, а с полной оптимизацией - 214

Re: WinAvr в вопросах и ответах
Добавлено: Пт ноя 26, 2010 13:35:07
AlexFisher
Reset писал(а):Всё бы хорошо, но симулятор по этой дряни не ходит нормально.
И что значит "ни чего не делает"? А а++ - это он считает "ничего"м?
Дело в том, что после инкремента эта переменная нигде не используется (не влияет на другие переменные) - поэтому операция выброшена.
Симулятор "ходит" уже по готовому коду - дизассемблируя на ходу и сопоставляя код согласно сишному. Отключите оптимизацию или пишите логичную программу.
По последней версии AVR
Добавлено: Пт ноя 26, 2010 13:36:59
Reset
Также замечено, мож людям пригодится - при подключении simulator2 (их 2 в последней студии 4.18SP3) - студия падает при выходе из симулятора если проект в GCC. При работе с симулятором без цифры - всё нормально.
Re: WinAvr в вопросах и ответах
Добавлено: Пт ноя 26, 2010 13:41:46
Reset
AlexFisher писал(а):Reset писал(а):Всё бы хорошо, но симулятор по этой дряни не ходит нормально.
И что значит "ни чего не делает"? А а++ - это он считает "ничего"м?
Дело в том, что после инкремента эта переменная нигде не используется (не влияет на другие переменные) - поэтому операция выброшена.
Симулятор "ходит" уже по готовому коду - дизассемблируя на ходу и сопоставляя код согласно сишному. Отключите оптимизацию или пишите логичную программу.
Не всегда так. Если переменная не объявлена как volatile - часто оптимизатор рубит защитные интервалы. В смысле, когда надо включить программный таймер на ожидание какого-то таймаута (на пример ожидания следующего байта по UART), а условие внешнее (ну не понятно же, досчитает он когда-нибудь, или на том конце всё хорошо и инкремент переменной равен декременту) - бывало у моего коллеги вырубало этот кусок оптимизация в IAR.
Не знаю как в GCC, но на всякий случай проверил volatile - отлично посылает подальше оптимизатор.
Re: WinAvr в вопросах и ответах
Добавлено: Пт ноя 26, 2010 13:53:11
ARV
вы сами решите для себя: какой смысл изменять ячейку ОЗУ, если результат этого изменения нигде никому не требуется?! история возникновения
volatile, как мне кажется, вами несколько искажена, но тем не менее, если вам необходимо, чтобы делалось что-то бессмысленное и бесполезное - вы просто обязаны об этом уведомить оптимизатор - он поймет

более того:
volatile просто необходимо указывать для всех глобальных переменных, которые используются и в прерываниях, и в обычных функциях.
что касается не хождения симулятора, то это опять-таки из-за оптимизатора: если коду в строке исходника ничего в реальности не соответствует (выкинуто) - по чем ходить-то прикажете?! отключите оптимизацию
-O0 и ходите по каждой строчке, сколько влезет

Re: WinAvr в вопросах и ответах
Добавлено: Пт ноя 26, 2010 14:06:38
Reset
ARV писал(а):вы сами решите для себя: какой смысл изменять ячейку ОЗУ, если результат этого изменения нигде никому не требуется?!
ARV писал(а):история возникновения
volatile, как мне кажется, вами несколько искажена, но тем не менее, если вам необходимо, чтобы делалось что-то бессмысленное и бесполезное - вы просто обязаны об этом уведомить оптимизатор - он поймет

более того:
volatile просто необходимо указывать для всех глобальных переменных, которые используются и в прерываниях, и в обычных функциях.
Несколько да. На самом деле было примерно как здесь (
https://groups.google.com/group/comp.la ... 1922?hl=ru&) пишут, ну и здесь (
http://alenacpp.blogspot.com/2006/04/volatile.html) по русски рассуждают (к стати - путная статейка по волетайлу, оченно советую тем, кто хочет "окунуться" в тему и поймать дзен по поводу этой переменной)
На уровне железа многие процессоры просто резервируют блок адресов памяти для портов ввода-вывода. Большинство процессоров имеют отдельное пространство адресов ввода-вывода, со специальными инструкциями для доступа туда, но это не универсально (на PDP-11 такого не было, например) и даже сейчас, производители железа могут предпочесть использовать для этого адресное пространство памяти, по разным причинам. Я сомневаюсь, что кто-то так делает на архитектуре 8086 - различные адресные ограничения делают это очень сложным. Я видел это на 8080, это очень частое решение на старой TI 9900. И это был единственный способ организовать ввод-вывод на наборе инструкций PDP-11, там просто не было отдельного адресного пространства ввода-вывода (Я думаю, то же самое верно и для VAX. И не забывайте, что большинство работы на С раньше проходило именно на этих двух процессорах).
//-------------------------------
Теперь рассмотрим один из первых последовательных портов, что я использовал: Intel 8051. Нормальным способом его инициализации было записать 0 три раза в порт управления. Если у вас MMIO, то код на С мог бы выглядеть примерно так:
Код: Выделить всё
unsigned char* pControl = 0xff24 ;
*pControl = 0 ;
*pControl = 0 ;
*pControl = 0 ;
Что прекрасно работало на всех компиляторах С. Но вы можете себе представить, что могла бы с этим сделать сама простая оптимизация.
Какбе - пруфлинк.
ARV писал(а):что касается не хождения симулятора, то это опять-таки из-за оптимизатора: если коду в строке исходника ничего в реальности не соответствует (выкинуто) - по чем ходить-то прикажете?! отключите оптимизацию
-O0 и ходите по каждой строчке, сколько влезет

Я поступил по другому - переключился на нормальный старый симулятор с симулятор2 в астудио и поставил волетайл переменную - всё работает как часы, максимальная степень оптимизации послушно слоняется по бесполезному циклу, разница в объеме стала теперь логичной 240Б без и 214 - с оптимизайией.
P.S. Вот что волетайл животворящий делает!
Re: WinAvr в вопросах и ответах
Добавлено: Пт ноя 26, 2010 14:18:15
ARV
Reset писал(а):Вот что волетайл животворящий делает!
воистину! аминь
P.S. природа зарождения volatile не интересна, т.к. четко понятен его смысл - уведомить компилятор, что обращение к переменной должно быть каждый раз, когда переменная упомянута в тексте. про порты - это все интересно, но есть и такие финты:
a = (b+3)*b; - если
b не-volatile, то она будет считана в регистр
один раз и затем этот регистр будет использован в вычислениях. если к моменту этого оператора значение
b уже лежало в каком-то регистре, то этот регистр и будет использован без лишних загрузок. однако, если переменная
b объявлена
volatile, то в процессе вычислений она будет
ДВАЖДЫ считана из ОЗУ. если эта перменная отображена на область адресов внешних устройств - может быть считано два РАЗНЫХ значения перменной со всеми вытекающими.

или вот еще, сравните:
if(a & a & a) c
if(PINB & PINB & PINB). в первом случае компилятор сделает по сути
if(a), а вот во-втором - нет: произойдет "определение дребезга единицы", т.к.
PINB - это
volatile-переменная
