Zynq7020 SDK上两个uart的设置问题

在Zynq7020开发板上,初始默认使用UART1进行裸机输出并无问题。然而,当尝试配置两个UART(UART0和UART1)时,SDK中的HelloWorld程序停止打印。虽然系统运行正常,但输出缺失。问题根源在于代码中E0000000是UART0的地址,需更改为UART1的地址以解决无输出问题。

硬件开发板默认的uart为uart1,我遇到过这个问题,在Vivado里设置uart1,裸机上输出是没有任何问题,但是一旦我设置了两个uart,既uart0,uart1,SDK里helloworld都无法打印,一开始我以为是系统死掉了,但是我看到电流,是系统已经跑起来了,可是为什么没有输出。之后看了一下代码,发现了猫腻。

原因就在这了,E0000000为uart0的地址,修改为uart1的地址即可。

<think>嗯,用户想了解如何在Zynq 7020PS用GPIO 14和15模拟UART,并写出代码。首先,我需要确认Zynq 7020PSGPIO是否支持模拟UART功能。记得ZynqPS部分有GPIO控制器,可以通过软件模拟UART,也就是所谓的bit-banging。 下来,用户可能需要的是基本的UART发送和收函数,使用两个GPIO引脚,一个作为TX,一个作为RX。但模拟UART需要注意时序,尤其是波特率。比如,常见的115200波特率对应的位时间大约是8.68微秒。这需要精确的延时,但ZynqPS没有硬件定时器,所以可能需要使用忙等待或者系统定时器。 然后需要考虑GPIO的初始化,设置引脚14为输出(TX),15为输入(RX)。在代码中需要配置MIO引脚的方向,并确保上拉电阻等设置正确,避免信号问题。 另外,用户可能需要中断或轮询的方式处理收。轮询的话,实时性可能不够,但代码简单。中断的话更高效,但配置起来复杂一些。根据用户的问题,可能先给出轮询的例子,因为更简单易懂。 代码结构方面,需要初始化GPIO,设置方向,然后实现发送字符和收字符的函数。发送函数需要按位输出,并遵循起始位、数据位、停止位的顺序。收函数需要检测起始位的下降沿,然后读取数据位。 需要注意的是,模拟UART的精度可能受系统负载影响,尤其是用忙等待延时的话。高波特率下可能会有问题,但低波特率比如9600可能更稳定。用户可能需要根据实际需求调整波特率。 最后,测试部分也很重要,可能需要回环测试或者连实际设备验证数据是否正确。用户可能需要示波器或逻辑分析仪来调试时序问题。 总结下来,步骤是:GPIO初始化,配置TX和RX方向,实现发送和收函数,处理时序,注意错误处理,比如超时检测。然后提供示例代码,用轮询方式,并提醒可能的时序偏差问题。</think>在Zynq 7020PS(Processing System)使用GPIO 14和15模拟UART通信(即"bit-banging")需要注意时序控制和GPIO配置。以下是基于Vivado SDK/Xilinx SDK的示例代码框架(使用C语言),分为发送和收两部分: --- ### 1. 硬件配置前提 - 确认GPIO 14和15已配置为PSMIO引脚(非PLEMIO) - 在Vivado中启用GPIO外设并连到MIO 14和15 - 引脚分配: - GPIO 14 作为UART TX(输出模式) - GPIO 15 作为UART RX(输入模式) --- ### 2. 示例代码 ```c #include "xparameters.h" #include "xgpio.h" #include "xil_printf.h" #include "sleep.h" // 定义GPIO参数 #define TX_PIN 14 #define RX_PIN 15 #define BAUDRATE 115200 #define BIT_DELAY (1000000 / BAUDRATE) // 单位:微秒 // GPIO实例 XGpio Gpio; // 初始化GPIO void uart_init() { XGpio_Initialize(&Gpio, XPAR_GPIO_0_DEVICE_ID); // TX引脚设为输出,RX引脚设为输入 XGpio_SetDataDirection(&Gpio, 1, (1 << RX_PIN) | (0 << TX_PIN)); XGpio_DiscreteWrite(&Gpio, 1, 1 << TX_PIN); // 初始保持高电平(空闲状态) } // 发送一个字节 void uart_send_byte(u8 data) { // 发送起始位(低电平) XGpio_DiscreteWrite(&Gpio, 1, 0 << TX_PIN); usleep(BIT_DELAY); // 发送8位数据(LSB first) for(int i = 0; i < 8; i++) { XGpio_DiscreteWrite(&Gpio, 1, ((data >> i) & 0x01) << TX_PIN); usleep(BIT_DELAY); } // 发送停止位(高电平) XGpio_DiscreteWrite(&Gpio, 1, 1 << TX_PIN); usleep(BIT_DELAY); } // 收一个字节(轮询方式) int uart_receive_byte(u8 *data) { // 检测起始位(下降沿) while(XGpio_DiscreteRead(&Gpio, 1) & (1 << RX_PIN)); // 等待低电平 usleep(BIT_DELAY / 2); // 在比特中间采样 // 检查是否仍为低电平(确认起始位) if(XGpio_DiscreteRead(&Gpio, 1) & (1 << RX_PIN)) return -1; usleep(BIT_DELAY); // 读取8位数据(LSB first) *data = 0; for(int i = 0; i < 8; i++) { *data |= ((XGpio_DiscreteRead(&Gpio, 1) >> RX_PIN) & 0x01) << i; usleep(BIT_DELAY); } // 检查停止位(高电平) if(!(XGpio_DiscreteRead(&Gpio, 1) & (1 << RX_PIN))) return -1; return 0; } // 示例主函数 int main() { uart_init(); u8 received_data; while(1) { if(uart_receive_byte(&received_data) == 0) { xil_printf("Received: 0x%02X\r\n", received_data); uart_send_byte(received_data); // 回传收到的数据 } } return 0; } ``` --- ### 3. 关键注意事项 1. **时序精度**:`usleep()`精度依赖系统时钟,实际波特率可能有偏差,建议使用硬件定时器优化 2. **中断优化**:收代码采用轮询方式,高波特率下可能丢数据,可改用中断检测起始位 3. **电平转换**:若连外部UART设备,需添加电平转换电路(如USB-TTL模块) 4. **引脚配置**:确保Vivado工程中GPIO Bank 1的电压与外部设备匹配(通常3.3V) --- ### 4. 性能优化建议 - 使用XScuTimer硬件定时器替代`usleep()`提高时序精度 - 对GPIO寄存器直操作(替代XGpio库函数)提升速度: ```c #define GPIO_BASEADDR XPAR_PS7_GPIO_0_BASEADDR // 写操作:*(volatile u32*)(GPIO_BASEADDR + 0x00) = value; // 读操作:value = *(volatile u32*)(GPIO_BASEADDR + 0x04); ``` 如果需要更详细的硬件配置或中断版本代码,可以进一步说明具体需求!
评论 3
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

smile_5me

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值