本帖最后由 suncat0504 于 2022-7-4 20:20 编辑
#申请原创#
之前测试连接SPI接口的液晶屏的时候,使用的是GPIO口模拟方式实现的。今天着手测试APM32E103的SPI设备。首先使用例程来测试SPI口的通讯,熟悉相关代码。例程中使用SPI作为从设备,由串口1发数据给SPI,同时SPI发数据给串口。从而实现串口和SPI之间的双祥通讯。打开工程、编译、下载,程序运行都正常。然后开始挂载SPI液晶屏,依旧使用其它GPIO口模拟的方式驱动。在程序中加入液晶屏的初始化、测试,经过测试也都正常。 然后把显示代码加到串口1与SPI的相互通讯中,显示通讯数据。代码如下: 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);
}
}
下载运行,结果运行中的显示为: 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);
}
}
编译、下载、运行。液晶显示为: 终于正常了。 这次的测试,给了自己一个教训。单片机执行速度很快,是微秒级的,在自己看来,这些都很短,在处理液晶显示的时候,花的时间可以忽略不计。然而在时序要求比较严格的地方,就可能造成无法预知的后果。这个情况,就像在有些I2C通讯的时候,如果出现了别的中断处理导致I2C通讯的延迟,等中断结束的时候,I2C通讯已经不能被正常执行了,是一样的道理。而且,自己也忽视了SPI双向通讯的特点,所出现这个结果太正常了。希望自己能牢牢记住这次的教训,避免下次再犯同样的错误。 在测试中,我还发现另外一个不解的问题,就是在下载了和串口有关的代码后(如这次的SPI测试),串口会在复位执行新下载的程序前,不断地向串口发出数据,以0x00居多,但没有规律。即使按下复位按钮不松开,发送也不会停止。在自己的印象中,执行复位,处于复位状态的微处理器是不应该工作的啊?怎么会发送串口数据呢?我的这个程序中的串口1和串口2都用了,但和串口2比,串口1使用了USART1_CK(PA8)这个信号,结果在复位状态下串口1不断发出数据,但串口2却没有。为了验证,把串口2也按照串口1方式初始化,使用USART2_CK(PA4),然后观察复位状态下串口2是否也不断发出数据。结果串口2也出现了不断发数据的情况。这个问题,我估计自己是解决不了了,只好告知极海的技术人员了。希望能解决。
|