Я изучаю программирование микроконтроллера STM32 с помощью платы STM32F4DISC-1. Я пытаюсь мигать светодиодом, подключенным к выводу PD14 контроллера STM32F407vg. В рамках упражнения я должен установить регистр режима порта GPIO, где 28-й бит должен быть установлен как выход, чтобы я мог поставить 1 для включения светодиода.
Переменная-указатель для регистра режима порта определяется, как показано ниже, она инициализируется базовым адресом + смещением.
uint32_t * pPortDModeReg = (uint32_t*)0x40020C00;
чтобы установить 28-й бит в 1 , я использую следующий оператор для очистки 28-го и 29-го битов перед установкой 28-го бита в 1.
* 2. настроить режим ввода-вывода в качестве выхода
очистить 28-й и 29-й биты, инвертировав & ing со сдвигом 011 влево на 28 бит*
*pPortDModeReg &= ~(3 << 28);
Я получаю следующую ошибку в IDE STM32CubeIDE на основе gcc.
../Src/main.c:36:4: **ошибка: недопустимые операнды для двоичного * (имеют 'int' и 'uint32_t ' {он же 'long unsigned int '}) 36 |
*pPortDModeReg &= ~(3 << 28);
Я даже пытался использовать выражение RHS как (uint32_t*), как показано ниже, но ошибка сохраняется.
pPortDModeReg &= (uint32_t *) (~(3 << 28));
**
Но для инструктора обучающего видео это утверждение строится без ошибок.
Играет ли со мной какая-либо настройка компилятора? , пожалуйста помоги.
Я даю ниже файл main.c для справки
#include <stdint.h>
// This program has been modified to blink the RED LED connected to
PD14 pin and with bitwise operators
int main(void) {
uint32_t *pClkCtrlReg = (uint32_t*)0x40023830;
uint32_t *pPortDModeReg = (uint32_t*)0x40020C00;
uint32_t *pPortDOutReg = (uint32_t*)0x40020C14;
//1. Enable clock for GPIOD peripheral in AHB1ENR ( SET the 3rd bit position)
*pClkCtrlReg |= (1<<3) /* Surprisingly , this line doesn't cause error */
/*configure the mode to set the GPIO pin 14 as output
// clear the 28th and 29th bits
*pPortDModeReg &= ~(3 << 28); /*This line causes error*/
// set the 28th bit
*pPortDModeReg |= (1> << 28);
Начните с выяснения того, что компилятор пытается вам сказать. Что означает «ошибка: недопустимые операнды для двоичного *»? В программировании на C мы говорим об унарных, бинарных и троичных операндах, в зависимости от того, принимают ли они 1, 2 или 3 операнда. Таким образом, бинарный оператор * будет *
с двумя операндами, также известный как умножение. Теперь, почему компилятор думает, что вы делаете умножение?
pClkCtrlReg |= (1<<3) / Удивительно, но эта строка не вызывает ошибки */
Оно делает. Отсутствие точки с запятой заставляет компилятор думать, что вы пишете одно выражение в нескольких строках:
*pClkCtrlReg |= (1<<3)*pPortDModeReg &= ~(3 << 28); // this is what the compiler sees
И поэтому он думает, что *
in (1<<3)*pPortDModeReg
— это умножение, бинарный оператор * вместо унарного * для косвенности.
Кроме того, вот набор других ошибок:
uint32_t *pClkCtrlReg = (uint32_t*)0x40023830;
Всякий раз, когда вы используете аппаратные регистры, вы обязательно должны добавлять volatile
квалификаторы, иначе вы можете получить всевозможные странные ошибки оптимизации. См. Как получить доступ к аппаратному регистру из прошивки? Из этой ссылки мы также можем узнать, что все целочисленные константы должны быть написаны с U
или u
в конце, чтобы предотвратить случайное получение целочисленных типов со знаком.
Это приводит нас к другому источнику ошибок 1 << 28
. Эта линия работает, но в основном не повезло. 1
является целочисленной константой и имеет знаковый тип int
. Пока он положительный, мы можем сдвинуться до 30-го бита. Если вместо этого мы попытаемся что-то вроде 1 << 31
установки MSB, мы вызовем ошибки неопределенного поведения, потому что теперь мы сдвигаем данные в знаковый бит безымянного, int
образованный 1
. Опять же, мы должны писать 1u << 31
, чтобы избежать ошибок.
Почему только левый операнд? Что ж, в написании нет ничего плохого, 1u << 31u
но операторы сдвига — это особый случай в C, поскольку они всегда возвращают результат того же типа, что и левый операнд. Обычные выражения C будут использовать неявное повышение типа, чтобы сделать оба операнда одного и того же типа, и тогда результат будет этого типа.
int main (void)
не имеет смысла в приложениях «голого железа» и RTOS MCU. Это так называемые автономные системы, и они никогда не возвращаются из функции main(). Потому что к кому они вернутся? Обычно все автономные системы void main (void)
вместо этого используют форму, определяемую реализацией. (Если вы используете gcc, компилируйте его -ffreestanding
при кодировании встроенных систем.)
Тагли
Арсенал
Мадаван Вишванатан
Мат
;
, что сбивает синтаксический анализатор и вызывает ошибку.Только я
Мадаван Вишванатан
Лундин
Только я
Мадаван Вишванатан
Только я