[APM32E103] 【APM32E103xE测评】+SPI接口测试感悟及发现的串口问题

[复制链接]
16|0
手机看帖
扫描二维码
随时随地手机跟帖
suncat0504|  楼主 | 2022-5-12 22:13 | 显示全部楼层 |阅读模式
本帖最后由 suncat0504 于 2022-5-12 22:16 编辑

#申请原创#

  之前测试连接SPI接口的液晶屏的时候,使用的是GPIO口模拟方式实现的。今天着手测试APM32E103SPI设备。首先使用例程来测试SPI口的通讯,熟悉相关代码。例程中使用SPI作为从设备,由串口1发数据给SPI,同时SPI发数据给串口。从而实现串口和SPI之间的双祥通讯。打开工程、编译、下载,程序运行都正常。然后开始挂载SPI液晶屏,依旧使用其它GPIO口模拟的方式驱动。在程序中加入液晶屏的初始化、测试,经过测试也都正常。

1

1
然后把显示代码加到串口1SPI的相互通讯中,显示通讯数据。代码如下:
int main(void)
{
    int no=0;
    /** Buffer Compare state */
    uint8_t state = FALSE;
    /** SPI receive Buf*/
    uint8_t rxDataBufSPI[DATA_BUF_SIZE]   = {0x00};
    /** USART receive Buf*/
    uint8_t rxDataBufUSART[DATA_BUF_SIZE] = {0x00};
   
    // LCD液晶初始化
    lcd_25696_init();
   
    // 测试液晶
    lcd25696_test();
   
    Delay(0x3000);
   
    clear_screen();
   
    APM_MINI_LEDInit(LED2);
    APM_MINI_LEDInit(LED3);
    APM_MINI_LEDOff(LED2);
    APM_MINI_LEDOff(LED3);

    USART_FullDuplex_Init();
    SPI_FullDuplex_Init();
   
    display_string_16x16_textmode(0, 0, (uint8_t *)"init usart2:");
   
    // 初始化串口2
//#ifdef USART2_FullDuplex
//    USART2_FullDuplex_Init();
//#else
    usart2_init();
//#endif
   
    display_string_16x16_textmode(12, 0, (uint8_t *)"end");   
   
    Delay(0x5000);
    //clear_screen();
   
    display_string_16x16(0, 2, (uint8_t *)"COM发送:");
    display_string_16x16(0, 4, (uint8_t *)"SPI接收:");
    display_string_16x16(0, 6, (uint8_t *)"Spi发送:");
    display_string_16x16(0, 8, (uint8_t *)"COM接收:");
    for (int i = 0; i < DATA_BUF_SIZE; i++)  {
        no=i+48;
        // 串口发送数据,因为串口1有问题,根据设置,选择串口1或者串口2
        #ifdef USART2_FullDuplex
            USART_TxData(USART2, no);
        #else
            USART_TxData(USART1, no);
        #endif
        display_alpha_char(i*16+80, 2, hexchar[no/16]);
        display_alpha_char(i*16+88, 2, hexchar[no%16]);

        
        // SPI发送数据
        SPI_WriteByte(no);
        display_alpha_char(i*16+80, 6, hexchar[no/16]);
        display_alpha_char(i*16+88, 6, hexchar[no%16]);

        
        // SPI收到数据
        while (SPI_I2S_ReadStatusFlag(SPI1, SPI_FLAG_RXBNE) == RESET);
        rxDataBufSPI[i] = SPI_I2S_RxData(SPI1);
        display_alpha_char(i*16+80, 4, hexchar[rxDataBufSPI[i]/16]);
        display_alpha_char(i*16+88, 4, hexchar[rxDataBufSPI[i]%16]);
        
        // 等待串口收到来自SPI发出的数据
        #ifdef USART2_FullDuplex
            /* Wait data is received by UART1 */
            while (USART_ReadStatusFlag(USART2, USART_FLAG_RXBNE) == RESET);
            rxDataBufUSART[i] = USART_RxData(USART2);
        #else
            /* Wait data is received by UART1 */
            while (USART_ReadStatusFlag(USART1, USART_FLAG_RXBNE) == RESET);
            rxDataBufUSART[i] = USART_RxData(USART1);
        #endif
        display_alpha_char(i*16+80, 8, hexchar[rxDataBufUSART[i]/16]);
        display_alpha_char(i*16+88, 8, hexchar[rxDataBufUSART[i]%16]);  
    }

    /** Compare receive Buffer*/
    state = BufferCompare(rxDataBufUSART, rxDataBufSPI, DATA_BUF_SIZE);

    /* Data is ok then turn on LED2 */
    if (state == 1)
    {
        APM_MINI_LEDOn(LED2);
    } else {
        APM_MINI_LEDOn(LED3);
    }

    while (1)
    {
        //APM_MINI_LEDToggle(LED3);
        Delay(0x7ffff);
    }
}
下载运行,结果运行中的显示为:

2

2
COM接收到的数据的第一个字节竟然是0x00,而不是臆想中的0x30。调整部分代码的执行顺序,依旧如此。
暂时没有解决,到了做饭点,去做饭。吃完晚饭后,坐下来想了想,例程中的测试是正常的,我的代码仅仅是增加一些显示测试数据的代码。再想到SPI通讯的特点,想起来是同时双向传递数据的,使用同一个CLK完成,而在我的代码中,在收发处理之间加入了很多处理代码,是不是这部分代码导致了通讯数据有延时,导致错位?马上调整代码为如下形式:
int main(void)
{
    int no=0;
    /** Buffer Compare state */
    uint8_t state = FALSE;
    /** SPI receive Buf*/
    uint8_t rxDataBufSPI[DATA_BUF_SIZE]   = {0x00};
    /** USART receive Buf*/
    uint8_t rxDataBufUSART[DATA_BUF_SIZE] = {0x00};
   
    // LCD液晶初始化
    lcd_25696_init();
   
    // 测试液晶
    lcd25696_test();
   
    Delay(0x3000);
   
    clear_screen();
   
    APM_MINI_LEDInit(LED2);
    APM_MINI_LEDInit(LED3);
    APM_MINI_LEDOff(LED2);
    APM_MINI_LEDOff(LED3);

    USART_FullDuplex_Init();
    SPI_FullDuplex_Init();
   
    display_string_16x16_textmode(0, 0, (uint8_t *)"init usart2:");
   
    // 初始化串口2
    usart2_init();
    display_string_16x16_textmode(12, 0, (uint8_t *)"end");   
   
    Delay(0x5000);
    //clear_screen();
   
    display_string_16x16(0, 2, (uint8_t *)"COM发送:");
    display_string_16x16(0, 4, (uint8_t *)"SPI接收:");
    display_string_16x16(0, 6, (uint8_t *)"Spi发送:");
    display_string_16x16(0, 8, (uint8_t *)"COM接收:");
    for (int i = 0; i < DATA_BUF_SIZE; i++)  {
        no=i+48;
        // 串口发送数据,因为串口1有问题,根据设置,选择串口1或者串口2
        USART_TxData(USART1, no);
        // SPI发送数据
        SPI_WriteByte(no);
        
        display_alpha_char(i*16+80, 2, hexchar[no/16]);
        display_alpha_char(i*16+88, 2, hexchar[no%16]);
        display_alpha_char(i*16+80, 6, hexchar[no/16]);
        display_alpha_char(i*16+88, 6, hexchar[no%16]);
        
        // SPI收到数据
        while (SPI_I2S_ReadStatusFlag(SPI1, SPI_FLAG_RXBNE) == RESET);
        rxDataBufSPI[i] = SPI_I2S_RxData(SPI1);
        
        // 等待串口收到来自SPI发出的数据
        /* Wait data is received by UART1 */
        while (USART_ReadStatusFlag(USART1, USART_FLAG_RXBNE) == RESET);
        rxDataBufUSART[i] = USART_RxData(USART1);
    }
   
    for (int i = 0; i < DATA_BUF_SIZE; i++)  {
        display_alpha_char(i*16+80, 4, hexchar[rxDataBufSPI[i]/16]);
        display_alpha_char(i*16+88, 4, hexchar[rxDataBufSPI[i]%16]);
        display_alpha_char(i*16+80, 8, hexchar[rxDataBufUSART[i]/16]);
        display_alpha_char(i*16+88, 8, hexchar[rxDataBufUSART[i]%16]);  
    }

    /** Compare receive Buffer*/
    state = BufferCompare(rxDataBufUSART, rxDataBufSPI, DATA_BUF_SIZE);

    /* Data is ok then turn on LED2 */
    if (state == 1)
    {
        APM_MINI_LEDOn(LED2);
    } else {
        APM_MINI_LEDOn(LED3);
    }

    while (1)
    {
        //APM_MINI_LEDToggle(LED3);
        Delay(0x7ffff);
    }
}
编译、下载、运行。液晶显示为:

3

3
终于正常了。
  这次的测试,给了自己一个教训。单片机执行速度很快,是微秒级的,在自己看来,这些都很短,在处理液晶显示的时候,花的时间可以忽略不计。然而在时序要求比较严格的地方,就可能造成无法预知的后果。这个情况,就像在有些I2C通讯的时候,如果出现了别的中断处理导致I2C通讯的延迟,等中断结束的时候,I2C通讯已经不能被正常执行了,是一样的道理。而且,自己也忽视了SPI双向通讯的特点,所出现这个结果太正常了。希望自己能牢牢记住这次的教训,避免下次再犯同样的错误。
  在测试中,我还发现另外一个不解的问题,就是在下载了和串口有关的代码后(如这次的SPI测试),串口会在复位执行新下载的程序前,不断地向串口发出数据,以0x00居多,但没有规律。即使按下复位按钮不松开,发送也不会停止。在自己的印象中,执行复位,处于复位状态的微处理器是不应该工作的啊?怎么会发送串口数据呢?我的这个程序中的串口1和串口2都用了,但和串口2比,串口1使用了USART1_CK(PA8)这个信号,结果在复位状态下串口1不断发出数据,但串口2却没有。为了验证,把串口2也按照串口1方式初始化,使用USART2_CK(PA4),然后观察复位状态下串口2是否也不断发出数据。结果串口2也出现了不断发数据的情况。这个问题,我估计自己是解决不了了,只好告知极海的技术人员了。希望能解决。
本来是想用SPI设备接口驱动SPI液晶屏的,但现在由于上面遇到的SPI双向通讯的问题,加上这个液晶屏虽然是采用SPI接口的,但是从现有资料上看,这个液晶屏只收数据,不向外发送数据,所以用开发板的SPI设备驱动液晶屏,看来是够呛了。但无论如何还是要试一试的,哪怕是把开发板的MISO接地,假装算作液晶屏返给开发板的数据来对待试试。如果SPI不行,USART方式没准还有希望呢。

使用特权

评论回复
您需要登录后才可以回帖 登录 | 注册

本版积分规则