目录
一.UART实验
UART介绍
UART是串行通信的一种协议和接口标准,全称是Universal Asynchronous Receiver/Transmitter,即通用异步收发器。UART分为发送器和接收器两部分,它们共用同一条数据线和时钟线,通过串行传输方式来实现数据的发送和接收。
UART的工作原理是将传输的数据分成一段段的数据包,每个数据包由一个起始位、8个数据位和一个或多个停止位组成。在发送端,将数据包转化为电信号信号发送出去,接收端将接收到的电信号转化为数据包。
UART的特点是数据传输速度较慢,但具有较高的可靠性和兼容性,因此在许多应用场景中仍被广泛使用。其中,常见的应用场景包括串口通信、UART通信、模拟信号转数字信号以及嵌入式系统等领域。同时,UART的实现也比较简单,可以使用各种现成的芯片和模块进行集成和开发。
并行通信和串行通信介绍
并行通信和串行通信是两种传输数据的方式。
并行通信是指同时传输多个数据位,每个数据位占用一个信号线,这些信号线在传输过程中保持同步。并行通信速度快,但需要很多信号线,对于长距离传输,信号失真和噪声等问题较为严重。常见的并行通信技术包括并行接口、总线接口、VME总线、PCI总线等。
串行通信是指逐位传输数据,每个数据位通过单个信号线传输,信号线之间不需要同步。串行通信速度相对较慢,但只需要较少的信号线,传输距离远时信号失真和噪声问题也较少。常见的串行通信技术包括RS-232、RS-422、RS-485、Ethernet、USB、HDMI等。其中,Ethernet和USB是目前使用最广泛的串行通信技术。
波特率介绍
波特率指的是每秒钟传输的比特数,也就是数据传输速率的一种度量单位。常见的波特率有1200、2400、4800、9600、19200、38400、57600、115200等,它们代表着每秒钟传输的比特数。
例如:波特率为9600,意味着每秒钟可以传输9600个比特。如果传输的数据是8位的ASCII码,每个字符需要8个比特表示,那么9600波特率每秒钟就能传输9600/8=1200个字符。
计算波特率的方法:波特率可以通过串行通信设备的配置参数设置,也可以通过以下公式计算:
波特率=数据传输速率/每个数据包中的比特数
例如:每个数据包中有8位比特,且数据传输速率为19200,那么波特率为19200/8=2400。
UART编程
#include "exynos_4412.h"
int main()
{
//设置GPA端口为uart端口TX和RX
GPA1.CON = GPA1.CON & (~(0xFF)) | (0x22);
// 设置uart的格式为帧格式,8位数据位 1位停止位无效验位 正常模式
UART2.ULCON2 = UART2.ULCON2 & (~(0x7F)) | (0x3);
// 设置UATR2 的接受和发送为轮询模式
UART2.UCON2 = UART2.UCON2 & (~(0xF)) | (0x5);
// 设置UART2 的波特率为115200
UART2.UBRDIV2 = 53;
UART2.UFRACVAL2 = 4;
while(1)
{
UART2.UTXH2 = 'A';
}
return 0;
}
#include "exynos_4412.h"
void UART_Init(void)
{
//设置GPA端口为uart端口TX和RX
GPA1.CON = GPA1.CON & (~(0xFF)) | (0x22);
// 设置uart的格式为帧格式,8位数据位 1位停止位无效验位 正常模式
UART2.ULCON2 = UART2.ULCON2 & (~(0x7F)) | (0x3);
// 设置UATR2 的接受和发送为轮询模式
UART2.UCON2 = UART2.UCON2 & (~(0xF)) | (0x5);
// 设置UART2 的波特率为115200
UART2.UBRDIV2 = 53;
UART2.UFRACVAL2 = 4;
}
void uart_send_byte(char Dat)
{
while(!(UART2.UTRSTAT2 & (1 << 1)));
UART2.UTXH2 = Dat;
}
char uart_recv_byte(void)
{
char Dat = 0;
if(UART2.UTRSTAT2 & 1)
{
Dat = UART2.URXH2;
return Dat;
}
else
{
return 0;
}
}
void uart_send_str(char * pstr)
{
while(*pstr != '\0')
uart_send_byte(*pstr++);
}
int main()
{
char RecDat = 0;
UART_Init();
#if 0
while(1)
{
RecDat = uart_recv_byte();
if(RecDat == 0)
{
}
else
{
RecDat = RecDat + 1;
uart_send_byte(RecDat);
}
}
#endif
while(1)
{
uart_send_str("Hello World\n");
}
return 0;
}
WDT实验
WDT简介
WDT 全称为 Watchdog Timer(看门狗定时器)。它是一种硬件定时器,在嵌入式系统中被广泛应用。WDT 的主要作用是在系统出现故障时进行恢复,防止系统崩溃或死锁。通俗来说,就像一只会定时“汪汪叫”的狗,如果系统持续工作而未出现异常,那么定时器就会被“喂狗”,定时又从头开始;如果系统出现故障或死锁,定时器就不会被“喂狗”,超时后会触发复位信号,使系统恢复到初始状态。
WDT 的工作流程通常分为以下四个步骤:
- 配置 WDT 定时器,确定定时时间。
- 启动 WDT 定时器,开始计时。
- 在程序的适当位置定时“喂狗”,重置 WDT 定时器的计时器。
- 如果 WDT 定时器超时,触发复位信号,将系统恢复到初始状态。
在实际使用 WDT 时,需要根据具体的应用场景选择适当的定时时间和定时器的重置位置,以保证系统在正常工作时不会误触发复位信号,同时在系统故障时能够及时恢复。需要注意的是,WDT 定时器的配置和使用具有一定的安全性风险,在使用 WDT 时应该慎重考虑,确保系统稳定性和安全性。
WDT实验步骤
ARM Cortex-A9处理器的WDT寄存器与其他处理器类似,但寄存器的名称和位域定义可能略有不同。下面是一个基于ARM Cortex-A9的WDT寄存器编程的示例:
首先,需要选择WDT的时钟源和定时器的计数周期。这可以通过配置WDT_MR寄存器实现。假设我们要选用CPU主时钟作为WDT的时钟源,而WDT的计数周期为2^16,那么可以这样设置:
#define WDT_MR (*((volatile uint32_t*)0x400E1454))
WDT_MR &= 0xF0FFFFFF; // 清除时钟源和定时器周期位
WDT_MR |= 0x05000000; // 使用主时钟作为WDT时钟源
WDT_MR |= 0x00010000; // 设置WDT定时器的计数周期为2^16
接下来,需要启用WDT,并设置定时器的工作模式。这可以通过WDT_CR寄存器实现。假设我们要启用WDT,并设置定时器在超时后立即重启系统,那么可以这样设置:
#define WDT_CR (*((volatile uint32_t*)0x400E1450))
WDT_CR |= 0x00000001; // 启用WDT
WDT_CR &= 0xFFFFFFFE; // 设置WDT定时器在超时后立即重启系统
最后,需要在程序中定时喂狗,防止WDT计时器超时。可以通过在代码中周期性地对WDT_SR寄存器写入0xA5000000,来清除计时器。这样可以使WDT定时器重新开始计时。下面是示例代码:
#define WDT_SR (*((volatile uint32_t*)0x400E1458))
while (1) {
WDT_SR = 0xA5000000; // 喂狗,防止WDT计时器超时
// TODO: 程序正常运行的代码
}
综上所述,一个基于ARM Cortex-A9处理器的WDT寄存器编程示例的完整代码如下:
#include <stdint.h>
#define WDT_MR (*((volatile uint32_t*)0x400E1454))
#define WDT_CR (*((volatile uint32_t*)0x400E1450))
#define WDT_SR (*((volatile uint32_t*)0x400E1458))
void main() {
WDT_MR &= 0xF0FFFFFF; // 清除时钟源和定时器周期位
WDT_MR |= 0x05000000; // 使用主时钟作为WDT时钟源
WDT_MR |= 0x00010000; // 设置WDT定时器的计数周期为2^16
WDT_CR |= 0x00000001; // 启用WDT
WDT_CR &= 0xFFFFFFFE; // 设置WDT定时器在超时后立即重启系统
while (1) {
WDT_SR = 0xA5000000; // 喂狗,防止WDT计时器超时
// TODO: 程序正常运行的代码
}
}