【问题标题】:LibOpenCM3 1-Wire over UART DMA STM32F1LibOpenCM3 1-Wire over UART DMA STM32F1
【发布时间】:2020-04-13 21:00:46
【问题描述】:

我刚开始使用 STM32F103 和 FreeRTOS + Libopencm3 了解嵌入式世界(继 Arduino、RPi 等)。我的第一个挑战是将温度传感器 DS18B20 与我的微处理器连接。 1-Wire 总线很容易理解,但不受本机支持,因此我按照您的建议使用 1-wire over UART 和 DMA。

DS18B20 在 USART2TX(+4k7 上拉 + 二极管)和 USART2RX 上有 DATA,VCC 到 5V 和 GND。

1-Wire 的初始化:

static void ow_init(void)
{
    // One-Wire
    // Already done : rcc_periph_clock_enable(RCC_GPIOA);
    gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART2_TX);
    gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_USART2_RX);
    usart_set_baudrate(USART2, 115200);
    usart_set_databits(USART2, 8);
    usart_set_stopbits(USART2, USART_STOPBITS_1);
    usart_set_mode(USART2, USART_MODE_TX);
    usart_set_parity(USART2, USART_PARITY_NONE);
    usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE);
    usart_enable(USART2);

    rcc_periph_clock_enable(RCC_DMA1);
}

1-Wire 复位:

uint8_t ow_reset(void)
{
    usart_disable_rx_dma(USART2);
    usart_disable_tx_dma(USART2);

    usart_set_baudrate(USART2, 9600);
    usart_set_databits(USART2, 8);
    usart_set_stopbits(USART2, USART_STOPBITS_1);
    usart_set_mode(USART2, USART_MODE_TX);
    usart_set_parity(USART2, USART_PARITY_NONE);
    usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE);

    usart_send(USART2, 0xf0);
    while(usart_get_flag(USART2, USART_SR_TC));
    uint8_t ow_presence;
    ow_presence = usart_recv(USART2);

    usart_set_baudrate(USART2, 115200);
    usart_set_databits(USART2, 8);
    usart_set_stopbits(USART2, USART_STOPBITS_1);
    usart_set_mode(USART2, USART_MODE_TX_RX);
    usart_set_parity(USART2, USART_PARITY_NONE);
    usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE);

    if(ow_presence != 0xf0)
    {
        return 1;
    }

    return 0;
}

获取暂存器:

void ow_convert_to_scratchpad(void)
{
    const uint8_t convert_T[] = {0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,  // 0xCC
                                 0x00, 0x00, 0xFF, 0x00, 0x00, 0x00, 0xFF, 0x00}; // 0x44

    dma_channel_reset(DMA1, DMA_CHANNEL7);
    dma_set_peripheral_address(DMA1, DMA_CHANNEL7, (uint32_t)&USART2_DR);
    dma_set_memory_address(DMA1, DMA_CHANNEL7, (uint32_t) convert_T);
    dma_set_number_of_data(DMA1, DMA_CHANNEL7, sizeof(convert_T));
    dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL7);
    dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL7);
    dma_set_peripheral_size(DMA1, DMA_CHANNEL7, DMA_CCR_PSIZE_8BIT);
    dma_set_memory_size(DMA1, DMA_CHANNEL7, DMA_CCR_MSIZE_8BIT);
    dma_set_priority(DMA1, DMA_CHANNEL7, DMA_CCR_PL_LOW);

    dma_enable_channel(DMA1, DMA_CHANNEL7);
    usart_enable_tx_dma(USART2);
}

uint16_t ow_get_scratchpad(void)
{
    const uint8_t read_scratch[] = {0x00, 0x00, 0xFF, 0xFF, 0x00, 0x00, 0xFF, 0xFF,  // 0xCC
                                    0x00, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0x00, 0xFF,  // 0xBE
                                    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF,
                                    0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF, 0xFF};

    uint8_t buf[8];

    dma_channel_reset(DMA1, DMA_CHANNEL6);
    dma_set_peripheral_address(DMA1, DMA_CHANNEL6, (uint32_t)&USART2_DR);
    dma_set_memory_address(DMA1, DMA_CHANNEL6, (uint32_t) buf);
    dma_set_read_from_peripheral(DMA1, DMA_CHANNEL6);
    dma_set_number_of_data(DMA1, DMA_CHANNEL6, sizeof(read_scratch));
    dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL6);
    dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL6);
    dma_set_peripheral_size(DMA1, DMA_CHANNEL6, DMA_CCR_PSIZE_8BIT);
    dma_set_memory_size(DMA1, DMA_CHANNEL6, DMA_CCR_MSIZE_8BIT);
    dma_set_priority(DMA1, DMA_CHANNEL6, DMA_CCR_PL_LOW);

    dma_channel_reset(DMA1, DMA_CHANNEL7);
    dma_set_peripheral_address(DMA1, DMA_CHANNEL7, (uint32_t)&USART2_DR);
    dma_set_memory_address(DMA1, DMA_CHANNEL7, (uint32_t) read_scratch);
    dma_set_number_of_data(DMA1, DMA_CHANNEL7, sizeof(read_scratch));
    dma_set_read_from_peripheral(DMA1, DMA_CHANNEL6);
    dma_disable_peripheral_increment_mode(DMA1, DMA_CHANNEL7);
    dma_enable_memory_increment_mode(DMA1, DMA_CHANNEL7);
    dma_set_peripheral_size(DMA1, DMA_CHANNEL7, DMA_CCR_PSIZE_8BIT);
    dma_set_memory_size(DMA1, DMA_CHANNEL7, DMA_CCR_MSIZE_8BIT);
    dma_set_priority(DMA1, DMA_CHANNEL7, DMA_CCR_PL_LOW);

    dma_enable_channel(DMA1, DMA_CHANNEL6);
    dma_enable_channel(DMA1, DMA_CHANNEL7);
    usart_enable_tx_dma(USART2);
    usart_enable_rx_dma(USART2);

    while(dma_get_interrupt_flag(DMA1, DMA_CHANNEL6, DMA_TCIF));

    uint16_t tt = 0;

    for(int i=0;i<32; i++)
    {
        uart1_printf("Bit : %d \n\r", buf[i]);
        if(buf[i] == 0xff)
        {
            tt = (tt >> 1) | 0x8000;
        }
        else
        {
            tt = tt >> 1;
        }
    }
    return tt;
}

static void demo_task(void *args)
{

    (void)args;

    for (;;) {
        uart1_printf("Hello\n\r");
        uint8_t p = ow_reset();
        uart1_printf("presence = %d\n\r", p);
        ow_convert_to_scratchpad();
        for(int i=0; i<5000000; i++)
        {
            __asm__("nop");
        }
        ow_reset();
        uint16_t t = ow_get_scratchpad();
        uart1_printf("t = %d \n\r", t);
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

最后是尝试到达 DS18B20 的任务

static void demo_task(void *args)
{

    (void)args;

    for (;;) {
        ow_reset();
        ow_convert_to_scratchpad();
        vTaskDelay(pdMS_TO_TICKS(500));
        ow_reset();
        uint16_t t = ow_get_scratchpad();
        uart1_printf("t = %d \n\r", t);
        vTaskDelay(pdMS_TO_TICKS(500));
    }
}

我收到一些位为 0xCC、0xBE、0xFF,但没有更多答案。

【问题讨论】:

  • 您能否更清楚地指出您的问题?你提供了大量的背景细节信息,这很好。但是,如果您能更清楚地指出交流的关键特征,将对读者有所帮助。你能从中创建一个最小的例子吗?或者为我们指出解决方案的工作点以及问题的开始?
  • 您必须从缩小问题范围开始。它在 UART 中还是在 DMA 中?做一个简单的程序,使用轮询而不是 DMA 从传入的 UART 数据填充数组。那样有用吗?如果是这样,问题出在 DMA 上。如果没有,请尝试将范围缩小到软件或硬件。
  • 好的,这是个好主意。我尝试了最简单的一个:禁用 DMA 并且只是 USART2 的基本配置。 PA2 和 PA3 分流。 usart_send(USART2, 0xFF); while(usart_get_flag(USART2, USART_SR_TC)); uart1_printf("Bit : %d \n\r", usart_recv(USART2)); 一次又一次的输出是“位:0”。我认为第一个问题已经出现了。
  • 我的 USART2 配置:rcc_periph_clock_enable(RCC_GPIOA); gpio_set_mode(GPIOA, GPIO_MODE_OUTPUT_50_MHZ, GPIO_CNF_OUTPUT_ALTFN_PUSHPULL, GPIO_USART2_TX); gpio_set_mode(GPIOA, GPIO_MODE_INPUT, GPIO_CNF_INPUT_FLOAT, GPIO_USART2_RX); usart_set_baudrate(USART2, 115200); usart_set_databits(USART2, 8); usart_set_stopbits(USART2, USART_STOPBITS_1); usart_set_mode(USART2, USART_MODE_TX_RX); usart_set_parity(USART2, USART_PARITY_NONE); usart_set_flow_control(USART2, USART_FLOWCONTROL_NONE); usart_enable(USART2);

标签: c embedded stm32 1wire


【解决方案1】:

好的,所以

rcc_periph_clock_enable(RCC_USART2);

丢失了,因此 USART2 无法完成工作。我现在可以发送和接收数据了。

除此行外,重置功能有效(无限期等待):

while(usart_get_flag(USART2, USART_SR_TC));

我不明白为什么传输完成后这个标志不是真的......但是我在 RX 线上有 0x00,所以我认为传感器正在响应(我希望......)

我的带有 DMA 的函数 ow_convert_to_scratchpad 看起来像被阻塞了。我不知道为什么...

我刚刚尝试(为了好玩...)通过硬编码发送的 0xCC、0x44、0xCC、0xBE 和来自传感器的读取但无应答 (0x00) 来替换整个 DMA。

【讨论】:

    【解决方案2】:

    我参加聚会有点晚了,但是……你有没有先尝试一些不那么复杂的东西? (我的意思是检查更简单)

    想询问单个 DS18B20 的地址?

    Reset bus and check presence.
    Send search ROM cmd (write byte 0xF0)
    loop 64 times reading address bits from LSB to MSB {
       read bit i
       read bit i complement
       check they are 1 and 0 or the other way around
       send bit i back to device so it sends you back the next bit
    }
    

    最后你得到了设备地址的 8 个字节。 1 字节族 0x28 48 位地址 1 字节 CRC8 来检查整个事情是否正确。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2014-07-09
      • 2019-04-26
      • 2017-09-04
      • 2013-10-31
      • 1970-01-01
      • 2018-11-21
      • 2019-09-24
      相关资源
      最近更新 更多