stm32f4 write/read 16bits 分成两个8位gpio口

stm32f4 write/read 16bits into two 8-bit gpio port

我尝试将 16 位数据写入两个选定的 8 位 gpio 端口。我必须拆分数据 LSB 和 MSB:

void LCD_write_command(uint16_t cmd) {
    GPIOD->ODR = cmd & 0x00ff; //lsb
    GPIOA->ODR = (GPIOA->ODR & 0x00ff) | (cmd >> 8); //msb
}

并读取数据:

uint16_t LCD_read_data(void) {
    (here is instruct gpio as input)
    volatile uint16_t data = 0;
    data  = (uint16_t)GPIOD->IDR & 0x00ff; //lsb
    data |= (uint16_t)GPIOA->IDR << 8 ; // msb
    (here is instruct gpio as output)
    return data;
}

当我用一个16位的gpio读写时一切正常:

 void LCD_write_command(uint16_t cmd) {
    GPIOD->ODR = cmd & 0xffff; 
}
uint16_t LCD_read_data(void) {
    volatile uint16_t data = 0;
    data  = (uint16_t)GPIOD->IDR & 0xffff; 
    return data;
}

我转达不知道我错过了什么。

您需要了解更多有关按位运算的知识。

  1. 写作

    void LCD_write_command(uint16_t cmd) {
       uint32_t tmp = GPIOD->ODR;
    
       tmp &= ~(0xff);
       tmp |= (cmd & 0x00ff);  
       GPIOD->ODR = tmp; //lsb
       tmp = GPIOA->ODR;
       tmp &= ~(0xff);
       tmp |= (cmd >> 8);
       GPIOA->ODR = tmp; //msb
    }
    

void LCD_write_command(uint16_t cmd) {
   *(volatile uint8_t *)&GPIOD->ODR = cmd & 0xff;
   *(volatile uint8_t *)&GPIOA->ODR = cmd >> 8; //msb
}

强制编译器使用 8 位存储指令。

在使用非字访问寄存器之前,如果您的微控制器允许,请检查 RM:

你的建议代码对我没有用,下面是用 LCD 处理的原始源代码:

void LCD_write_command(uint16_t cmd) {
    GPIOB->BRR = LCD_CS;       // LCD_CS low (chip select pull)
    GPIOB->BRR = LCD_RS;       // LCD_RS low (register select = instruction)
    //GPIOA->ODR = cmd;         // put cmd to PortA (full length)
    // put cmd [0..12] bits to PortA (actual LCD_DB00..LCD_DB12)
    // put cmd [13..15] bits to PortB (actual LCD_DB13..LCD_DB15)
    GPIOA->ODR = cmd & 0x1fff;
    GPIOB->ODR = (GPIOB->ODR & 0xfff8) | (cmd >> 13);
    GPIOB->BRR = LCD_WR;       // pull LCD_WR to low (write strobe start)
    // Write strobe 66ns long by datasheet. GPIO speed on STM32F103 at 72MHz slower -> delay is unnecessary
    // asm volatile ("nop");
    GPIOB->BSRR = LCD_WR;      // pull LCD_WR to high (write strobe end)
    GPIOB->BSRR = LCD_CS;      // LCD_CS high (chip select release)
}

我检查了RM,我可以在8位,半字和字上操作。

wtite_bits(uint16_t cmd)
{
    uint32_t data = GPIOA -> ODR;

    data &= ~(0x1fff);
    data |= cmd & 0x1fff;
    GPIOA -> ODR = data;

    data = GPIOB -> ODR;
    data &= ~(0x0007);
    data |= (cmd & 0x8fff) >> 13;
    GPIOB -> ODR = data;
}

保留寄存器中的其他位