2010-04-16 6 views
8

У меня есть адрес памяти определенного регистра (адрес LCDCW1 - C000).записывать данные для регистрации

гр коды:

#define LCDCW1 0xC000 

*LCDCW1=0x31; 

я просто хочу, чтобы записать данные в этот регистр. Коды имеют проблемы, как их исправить?

thx!

+1

какой компилятор/платформа? – Andrey

+0

@Andrey: 8051, компилятор: ICC8051 – martin

+0

Код as is не компилируется, потому что '0xc000' не является указателем, а для оператора' * 'требуется операнд указателя. –

ответ

18

Вы можете, как и другие предложили, объявить соответствующий указатель, т.е.

volatile uint32_t *reg = (volatile uint32_t *)0xc000; 

Обратите внимание, что я добавил volatile. Это всегда хорошая идея при чтении или записи аппаратных регистров, поскольку она гарантирует, что каждый доступ, который вы выполняете в коде C, действительно отображается в сгенерированном коде.

Однако, я обычно предпочитаю писать макросы, как этот

#define READ_LCDCW1() ... 
#define WRITE_LCDCW1(value) ... 

, а затем заполнить их с использованием соответствующих Gcc ПКР. Мне это нравится лучше, чем прямое использование указателей, потому что:

  • Я думаю, что они лучше читают в коде, идентифицируя, что я делаю, читая регистр, вместо того, чтобы сосредоточиться на том, как я это делаю.
  • Некоторые регистры требуют многостадийного процесса для чтения с аппаратного обеспечения. Это легко скрывается в макросах этого стиля, и основная часть моего кода по-прежнему относится к регистрам, которые меня интересуют, а не к сложному способу, с помощью которого аппаратное обеспечение меня трогает.
  • Наконец, используя asm, я точно знаю, как я обращаюсь к регистру. Иногда есть специальные инструкции или адресные пространства, необходимые для доступа к регистру, которые обычно не могут быть сгенерированы компилятором C.
  • Даже если вы не согласны с мотивацией использования операторов asm, я бы по-прежнему предлагал переносить ваши обращения к регистру в макросы (или встроенные функции), подобные этим.

В вашем случае, простейшие определения должны быть:

#define LCDCW1_ADDR  0xc000 
#define READ_LCDCW1()  (*(volatile uint32_t *)LCDCW1_ADDR) 
#define WRITE_LCDCW1(val) ((*(volatile uint32_t *)LCDCW1_ADDR) = (val)) 
+0

+1 для соответствующего (и слишком часто забытого) использования «изменчивого». – JustJeff

+0

См. Комментарий @ Schedler ниже для интересного документа о том, как большинство компиляторов не могут правильно реализовать 'volatile' в различных сложных случаях. –

+0

Используйте 'uint32_t' и т. Д. Вместо' long'. –

0

Я не знаю, что означает LCDCW1, но писать на постоянной адрес:

*(int*)0xC000 = 42; 

Отрегулировать в соответствии с (ваш регистр не может быть ИНТ размера).

1

Предполагая, что регистр имеет такой же размер, как long:

volatile long * ldccw1 = (long*)0xc000; 

*lcdcw1 = myValue; 
+0

@mouviciel: мое решение совершенно одинаково, но есть ошибка: требуется выражение указателя, знаете ли вы, почему? – martin

+0

@martin: Можете ли вы опубликовать свой код, который дает ошибку? – Naveen

+0

Указатели на внешние регистры должны быть «изменчивыми». – caf

1

LCDCW1 только целое значение. Вы не можете сделать *. Вам нужно наложить его на целочисленный (или введите вам) указатель, а затем использовать его. Например: *(int*)LCDCW1=0x31;

+0

Используйте 'uint16_t' и т. Д. Вместо' int'. –

4

Я считаю, что с осторожностью относиться к использованию ключевого слова volatile в порядке.

Иногда (часто) то, что компилятор считает летучим, не является тем, что предполагал программист (и наоборот).Рекомендуется всегда проверять полученный машинный код, когда используется ключевое слово volatile, чтобы избежать сюрпризов.

Дополнительную информацию см., Например, http://www.cs.utah.edu/~regehr/papers/emsoft08-preprint.pdf

+0

Это очень хорошая бумага. Его предлагаемая техника для надежной работы в компиляторах C является интересной, но я думаю, что они хуже с точки зрения читаемости, чем просто предоставление пары макросов для чтения/записи для каждого регистра, как я предлагаю в своем ответе на этот пост , –

Смежные вопросы