Полная версия этой страницы:
2 байта в AVR
Вопрос собственно в следующем:
разработана плата (и что плохо изготовлена), где есть связка Atmega128 и термодатчик MAX6630
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2577/t/alВыход термодатчика - 13 бит (12+знак) и еще мусор до 2 байт (по spi).
как сравнить и обработать данные в восьмибитном микроконтроллере?
C чем именно сравнить и как обработать ? На каком языке надо ?
arttab
Dec 24 2007, 02:49
Организовать хранение 2 Б +
Цитата
мусор до 2 байт
Устроняйте пробел в своих знаниях иначе дальше будет хуже ( у AVR АЦП 10 бит, а разрядность таки 8).
Расскажи поподробнее, что бы ты делал с данными, если бы они были восьми- (или менее) разрядными.
Тогда можно дать конкретный совет, что делать при большей разрядности. Без этого вопрос очень неконкретный и ответа ждать придётся долго.
первоначально планировал сравнение значения температуры с пороговым значением.
немного поразмыслив, понял,что для этого необходимо сравнить сначала старший байт со старшим байтом опорного значения.
если старшие байты равны, то надо сравнивать младшие.
но потом пришло следующее требование - вывод температуры на знакосегментный индикатор. т.е. для этого надо преобразовать значения в двоично-десятичный код
а как?
работаю avrstudio+winavr на с
Попробуйте потестировать в отладчике мою функцию
unsigned int hex2bcd (unsigned char hex)
{
unsigned char i;
unsigned int bcd=0;
for(i=0;i<8;i++) {
if ((bcd & 0x0F) >= 0x05) bcd += 0x03;
if ((bcd & 0xFF) >= 0x50) bcd += 0x30;
bcd <<= 1;
if ((hex & 0x80)==0x80) bcd |= 0x01;
hex <<= 1;
}
return bcd;
}
Писано это около года назад, не помню где то в сети отрыл алгоритм быстрого преобразования hex to bcd, как раз с целью вывода на жки. Сюдя по тому что взято из рабочей проги, должно работать.
arttab
Dec 26 2007, 01:28
Довольно странные вопросы. Если пользуетесь Си компилятором, то надо Си знать. Если бы Вы знали Си, то вопрос как хранить более 8 бит не возникло.
Работа программиста не сводиться к поиску готовых решений и скачки их с инета. Требуется понимание предоставляемых Вам возможностей и умение ими пользоваться.
Советую перечитать курс по микропроцессорам, языку Си, доки по AVR, разобраться в выложенным Algol примеры и изучить компилятор.
Цитата(Algol @ Dec 25 2007, 14:22)

отрыл алгоритм быстрого преобразования hex to bcd, как раз с целью вывода на жки.
Работает. Только вот как - нифига не понял
alexander55
Dec 26 2007, 05:52
Цитата(pimen @ Dec 24 2007, 02:37)

Если работаете с С используйте для 16 битных данных типы unsigned int и int.
Все Ваши проблемы решит компилятор.
Снимаю шляпу перед автором алгоритма. Красота-а-а-а!
На Си попробовать было негде - сваял процедурочку на VBA. Расширил до 16 разрядов. Алгоритм потенциально расширяем на любое количество разрядов. Вы будете смеяться, но я его понял! Правда только после того, как запустил под отладчиком.
В общем СУПЕР! Рекомендую программистам всех времён, народов и языков.
Побежал реализовывать на ассемблере.
Ниже приведена ассемблерная реализация алгоритма для MSC-51 (в AVR пока не силён).
В примере преобразуется десятичное число 23456.
Удлинняет код та особенность, что "полезные" операции можно выполнять только с аккумулятором.
При попытке перевести реализацию на AVR столкнулся с проблемой - не могу найти операцию двоично-десятичной коррекции (в нижеприведеном коде это команда DA). Это мне так не повезло или такой операции у AVR вообще нет?
start:
mov r3,#0 ; результат старший байт
mov r4,#0 ; результат средний байт
mov r5,#0 ; результат младший байт
mov r6,#05bh ; исходные данные старший байт
mov r7,#0a0h ; исходные данные младший байт
mov r0,#16 ; счётчик циклов
cycle:
mov a,r7
rlc a
mov r7,a
mov a,r6
rlc a
mov r6,a
mov a,r5
addc a,r5
da a
mov r5,a
mov a,r4
addc a,r4
da a
mov r4,a
mov a,r3
addc a,r3
da a
mov r3,a
djnz r0,cycle
Всех с наступившим Новым Годом!
написал прогу к вышесказанному
#include <avr/io.h>//mega128
char U,L;
void SPI_read(void)
{
SPCR=0x50;
SPDR=0xaa;
while(SPSR==0x00)
{ }
U=SPDR;
SPDR=0xaa;
while(SPSR==0x00)
{ }
L=SPDR;
SPCR=0x00;
}
void main(void)
{ PORTB&=0xDF;//spi fpga
SPI_read();
PORTB|=0x20;
//...сравнение значений температур с пороговым
PORTB&=0xEF;//spi rf
SPI_read();
PORTB|=0x10;
}
здесь сначала читается первый байт, потом второй байт из цифровых термометров
если я пишу это в переменную типа int, то все равно могу записать только 1 байт:
т.к. регистр spi расчитан на байт информации, то требуется новый запуск модуля spi для чтения информации с датчиков
при последующем чтении из регистра и записи информации в переменную предидущии данные естественно удаляются
как дописать данные в туже переменную?
или может подскажите идею или другую программную реализацию
жду ответов
--------------------------------------------------
щас читаю 3 книги: 2 по авр и по с....
прочитать например так:
(старший байт первый)
Код
/**
* Отправить \a send по SPI
* \return принятое по SPI значение
*/
unsigned char spi(unsigned char send);
....
{
int temp;
int porog;
...
temp = spi(0);
...
...
temp = (temp<<8)|spi(0);
...
if (temp == porog)
{
...
}
...
}
slanted
Jan 3 2008, 11:51
Цитата(pimen @ Dec 24 2007, 03:37)

Вопрос собственно в следующем:
разработана плата (и что плохо изготовлена), где есть связка Atmega128 и термодатчик MAX6630
http://www.maxim-ic.com/quick_view2.cfm/qv_pk/2577/t/alВыход термодатчика - 13 бит (12+знак) и еще мусор до 2 байт (по spi).
как сравнить и обработать данные в восьмибитном микроконтроллере?
Для этого придуман флаг переноса и соответствующие инструкции, учитывающие его (sub/sbc, cp/cpc).
Цитата(slanted @ Jan 3 2008, 14:51)

Для этого придуман флаг переноса и соответствующие инструкции, учитывающие его (sub/sbc, cp/cpc).
а как это реализуется/используется на С в AVRstudio?
slanted
Jan 3 2008, 16:36
Цитата(pimen @ Jan 3 2008, 18:57)

а как это реализуется/используется на С в AVRstudio?
Теоретически, оно должно само уметь обсчитывать стандартные сишные типы с помощью этих инструкций. WinAVR, к примеру, точно умеет. А вопрос-то был про восьмибитки вообще, я на него и ответил.
ps. Собственно, подобные инструкции есть везде, в x86 тоже.
ЛЮДИ!!!!
Объясните!
есть программа:
#include <avr/io.h>
int T=0x0;
main ()
{
T=(0b10001100<<8)>>3;
}
это нечто выдает значение Т=0b1111000110000000, хотя должен 0b0001111000110000.
если заменить сдвиг право на 3 на деление на 0b1000, то результат все равно 0b1111000110000000.
деление и сдвиг просто числа 0b1000110000000000 дает правильные результаты.
что я не учел??????????
Цитата(pimen @ Jan 6 2008, 03:02)

это нечто...
Главная ошибка - Вы начали использовать "нечто" пытающееся эмулировать дебильную бинарную запись при наличии в языках много более удобных средств, например, возможности поименовать биты. Разбираться (только зачем - правильнее не пользоваться) можете начинать с реализации этой самой 0b....
Потенциальная ошибка - препроцессор особым умом обычно особо не отличается, посему не не искушайте его и пользуйтесь не менее выразительным " <<( 8-3 )" а не "(<<8)>>3"
Примечание - разрядность констант не резиновая и по умолчанию чаще всего 16bit, посему нежели в будующем потребуется большая, то не забудте указать сие явно через 'L'.
C некоторой долей вероятности основываясь на типичных ошибках в реализации макросов на основе которых построено "нечто" можете попробовать:
T=(0b10001100) << (8-3);
Цитата
T=(0b10001100<<8)>>3;
...
выдает значение Т=0b1111000110000000, хотя должен 0b0001111000110000.
И что тут не правильного? Было 2 нуля справа, стало 7. Как раз сдвиг влево на 5.
А с единичками в старших разрядах что-то напутано:-)
slanted
Jan 6 2008, 12:12
Цитата(zltigo @ Jan 6 2008, 05:47)

Главная ошибка - Вы начали использовать "нечто" пытающееся эмулировать дебильную бинарную запись при наличии в языках много более удобных средств, например, возможности поименовать биты. Разбираться (только зачем - правильнее не пользоваться) можете начинать с реализации этой самой 0b....
Потенциальная ошибка - препроцессор особым умом обычно особо не отличается, посему не не искушайте его и пользуйтесь не менее выразительным " <<( 8-3 )" а не "(<<8)>>3"
Примечание - разрядность констант не резиновая и по умолчанию чаще всего 16bit, посему нежели в будующем потребуется большая, то не забудте указать сие явно через 'L'.
C некоторой долей вероятности основываясь на типичных ошибках в реализации макросов на основе которых построено "нечто" можете попробовать:
T=(0b10001100) << (8-3);
И где тут хоть один макрос?
Кстати, >>(8-3) сработает, но по совсем другой причине.
Цитата(pimen @ Jan 6 2008, 05:02)

int T=0x0;
main ()
{
T=(0b10001100<<8)>>3;
}
это нечто выдает значение Т=0b1111000110000000, хотя должен 0b0001111000110000.
если заменить сдвиг право на 3 на деление на 0b1000, то результат все равно 0b1111000110000000.
деление и сдвиг просто числа 0b1000110000000000 дает правильные результаты.
что я не учел??????????
Проблема в том, что: а) стандарт Си не специфицирует, будет ли ">>" арифметическим сдвигом, или логическим; б) не специфицируется размер int'а, который в данном случае составляет 16 бит. В результате сдвига на 8 влево, 0b10001100 превращается в 0x8C00, которое содержит единицу в знаковом бите (типа это отрицательное число). Сдвиг вправо, который как оказалось, в данном случае арифметический, размазывает эту единицу по старшим битам числа чтобы сохранить отрицательность. В результате имеем то, что имеем.
При сдвиге "просто числа" 0b1000110000000000 такого не происходит, потому что данная реализация компилятора считает константы данного вида unsigned, и генерирует для них логический сдвиг.
Цитата(slanted @ Jan 6 2008, 14:03)

И где тут хоть один макрос?
Прибамбасы (0b.... ) штатными средствами компиляторов не поддерживаются и в этом случае реализуются твердыми последователями ассемблеров не имеющих поддержки макросов на на макросах

- вот такой парадокс.
Еще вопрос по С:
использовал оператор goto. Сам оператор находится в подпрограмме, метка находится в main(). Компилятор пишет ошибку.
Если переношу оператор goto в main(), то все нормально.
что за ерунда?
mdmitry
Jan 10 2008, 20:48
Цитата(pimen @ Jan 10 2008, 23:22)

Еще вопрос по С:
использовал оператор goto. Сам оператор находится в подпрограмме, метка находится в main(). Компилятор пишет ошибку.
Если переношу оператор goto в main(), то все нормально.
что за ерунда?
Прочитать книгу по языку С и понять назначение оператора goto в языке. В ассемблере переход не запрещен из функции, программирование на С структурное и выход из функции должен быть корректно оформлен (очистка стека и другое).
slanted
Jan 10 2008, 22:28
Цитата(pimen @ Jan 11 2008, 00:22)

Еще вопрос по С:
использовал оператор goto. Сам оператор находится в подпрограмме, метка находится в main(). Компилятор пишет ошибку.
Если переношу оператор goto в main(), то все нормально.
что за ерунда?
Так задумано. Если хотите прострелить себе ногу -- прочитайте про setjmp/longjmp, которым такое поведение эмулируется.
alexander55
Jan 11 2008, 08:34
Цитата(pimen @ Jan 10 2008, 23:22)

Еще вопрос по С:
использовал оператор goto. Сам оператор находится в подпрограмме, метка находится в main().
Это что за издевательство ?
Подумайте, что будет со стеком ?
PS. Мой Вам совет - забудьте про goto и никогда не вспоминайте .
по поводу оператора goto, пользуясь вашими советами, забуду.
Подскажите, как корректно переместиться из подпрограммы в main()
структура программы приведена ниже:
void hot(void)
{
//отсюда надо попасть в main()
}
void compare(void)
if (....)
{
hot()
}
SIGNAL(SIG_OVERFLOW1)
{
...
compare()
...
}
main()
{
// сюда надо перескочить из hot()
}
alexander55
Jan 11 2008, 10:34
Цитата(pimen @ Jan 11 2008, 12:35)

по поводу оператора goto, пользуясь вашими советами, забуду.
Подскажите, как корректно переместиться из подпрограммы в main()
структура программы приведена ниже:
void hot(void)
{
//отсюда надо попасть в main()
}
void compare(void)
if (....)
{
hot()
}
SIGNAL(SIG_OVERFLOW1)
{
...
compare()
...
}
main()
{
// сюда надо перескочить из hot()
}
Давайте уточним задачу.
По некоторому прерыванию SIGNAL(SIG_OVERFLOW1)
при выполнении каких-то условий (скажем аварийных), Вы быстро должны произвести какие-то действия в hot() и завершить выполнение прерывания.
Так или что-то еще осталось за кадром ?
PS. Вспомнил про обсуждения на эту тему
http://electronix.ru/forum/index.php?showt...&hl=*goto*#
Цитата(alexander55 @ Jan 11 2008, 13:34)

Давайте уточним задачу.
По некоторому прерыванию SIGNAL(SIG_OVERFLOW1)
при выполнении каких-то условий (скажем аварийных), Вы быстро должны произвести какие-то действия в hot() и завершить выполнение прерывания.
Так или что-то еще осталось за кадром ?
PS. Вспомнил про обсуждения на эту тему
http://electronix.ru/forum/index.php?showt...&hl=*goto*#Вы совершенно правильно поняли
в hot() происходит выключение источников, потом в main(), пока есть авария (в данном случае перегрев), ждем устранение аварийного фактора, и поехали дальше
спасибо за ссылку
alexander55
Jan 11 2008, 12:12
Цитата(pimen @ Jan 11 2008, 14:42)

Вы совершенно правильно поняли
в hot() происходит выключение источников, потом в main(), пока есть авария (в данном случае перегрев), ждем устранение аварийного фактора, и поехали дальше
В main Вы попадете по окончании прерывания без всяких фокусов (причем с корректным стеком).
Если Вам надо заблокировать какие-то действия в прерывании, установите флаг аварии при выходе за допустимые пределы и анализируя этот флаг не выполняйте, что не требуется.
После устранения аварии этот флаг сбросьте (подозреваю, что он уже существует).
Вот и все.
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.