定时器、PWM定时器、UART串口通信

发布于:2024-04-19 ⋅ 阅读:(29) ⋅ 点赞:(0)

我要成为嵌入式高手之4月15日ARM第八天!!
————————————————————————————

定时器

        S3C2440A 有 5 个 16 位定时器。其中定时器 0、1、2 和 3 具有脉宽调制(PWM)功能。定时器 4 是一个无 输出引脚的内部定时器。定时器 0 还包含用于大电流驱动的死区发生器。

使用s3c2440的时钟4实现1毫秒的定时

定时器配制寄存器 0(TCFG0)

预分频寄存器

定时器配制寄存器 1(TCFG1)

分频寄存器

定时器输入时钟频率 = PCLK / {预分频值+1} / {分频值}

                                {预分频值} = 0~255

                                {分频值} = 2, 4, 8, 16

定时器控制寄存器 1(TCON)

定时器 4 计数缓冲寄存器(TCNTB4)

对算出来的计数器值(2500)的备份

定时器 4 计数监视寄存器(TCNTO4)

很少用到

设置中断寄存器INTMOD、INTMSK

将中断寄存器设置为定时器4

void timer4_init(void)
{
	TCFG0 |= (19 << 8);//预分频值为4
	//TCFG1 |= (1 << 16);//分频值为4

	TCON |= (1 << 22);
	TCNTB4 = 2500;//设置计数的值
	TCON |= (1 << 21);
	TCON &= ~(1 << 21);//先置1再置0将计数值修改进去

	//打开中断
	INTMOD &= ~(1 << 14);
	INTMSK &= ~(1 << 14);
	
	TCON |= (1 << 20);//打开定时器
}

PWM定时器

多出一个比较寄存器,相当于 TCNTB 控制周期,TCMPB控制占空比

在此用蜂鸣器调制PWM

用GPB0实现周期400hz,占空比50%的方波

参数设置与定时器4差不多

此外还需要设置蜂鸣器GPIO

端口 B 控制寄存器(GPBCON)

int counter0 = 0;

void timer0_init(void)
{
	//设置蜂鸣器GPIO
	GPBCON |= (2 << 0);

	TCFG0 |= (9 << 0);//预分频值为10 = 5M
	TCFG1 |= (1 << 0);//分频值为4 = 1.25M

	TCON |= (1 << 22);
	TCNTB0 = 3125;//设置计数的值 = 400HZ
	TCNTB0 = 3125 / 2;//设置占空比为50%
	
	TCON |= (1 << 3) | (1 << 2);//(1 << 2)由高电平开始
	TCON |= (1 << 1);
	TCON &= ~(1 << 1);//先置1再置0将计数值修改进去

	//打开中断
	INTMOD &= ~(1 << 10);
	INTMSK &= ~(1 << 10);
	
	TCON |= (1 << 0);//打开定时器
}

int timer0_handle(void)
{
	++counter0;
	if (counter0 >= 1000)
	{
		ledAllNor();
		counter0 = 0;
	}		
}

UART串口通信

        S3C2440A 的每个 UART 包括 7 种状态(Tx/Rx/错误)信号:溢出错误、奇偶校验错误、帧错误、断点、接收 缓冲器数据就绪、发送缓冲器空以及发送移位器空,全部都由相应 UART 状态寄存器(UTRSTATn/UERSTATn) 标示。

我们主要用到接收缓冲区数据中断

外设总线:APB

要发送的数据先写入发送缓冲区,然后通过发送移位器一个字节一个字节发;接收亦如此


UART 方框图(带 FIFO)

        

        波特率时钟是通过 16 和由 UART 波特率分频寄存器(UBRDIVn)指定的 16 位分频系数来分频源时钟(PCLK,FCLK/n 或 UEXTCLK)产生的。 UBRDIVn 由下列表达式决定:

UBRDIVn = (int)( UART 时钟 / ( 波特率 × 16) ) - 1

端口 H 控制寄存器(GPHCON,GPHDAT,GPHUP)

在此要将GPH2和GPH3设置为串口 发送 / 接收 模式

UART 线路控制寄存器(ULCON)

UART 控制寄存器(UCON)


在此不用管FCLK,选择PCLK

Tx发送中断类型:缓冲区一变成空,就产生中断

Rx接收中断类型:设置为脉冲类型

……

UART TX/RX 状态寄存器

用来查询的

UART 发送缓冲寄存器(保持寄存器和 FIFO 寄存器)

发送数据时进行修改

UART 接收缓冲寄存器(保持寄存器和 FIFO 寄存器)

UART 波特率分频寄存器

要进行计算得出波特率

        波特率时钟是通过 16 和由 UART 波特率分频寄存器(UBRDIVn)指定的 16 位分频系数来分频源时钟(PCLK,FCLK/n 或 UEXTCLK)产生的。 UBRDIVn 由下列表达式决定:

UBRDIVn = (int)( UART 时钟 / ( 波特率 × 16) ) - 1

例如,如果波特率为 115200 bps 并且 UART 时钟为 40 MHz,UBRDIVn 为:

UBRDIVn = (int)(40000000 / (115200 x 16) ) - 1

                = (int)(21.7) - 1 [取最接近的整数]

                = 22 - 1 = 2

void uart0_init(void)
{
	unsigned int t;

	GPHCON |= (2 << 4) | (2 << 6);

	t = ULCON0;
	t &= ~(1 << 6);
	t &= ~(7 << 3);
	t &= ~(1 << 2);
	t |= (3 << 0);
	ULCON0 = t;

	t = UCON0;
	t &= ~(3 << 10);
	t &= ~((1 << 8) | (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4));
	t |= (1 << 2) | (1 << 0);
	UCON0 = t;
	
	UBRDIV0 = 325;
}

发送一个字符: 

void uart0_send_char(unsigned char data)
{
	UTXH0 = data;
	while ((UTRSTAT0 & (1 << 1)) == 0);
	//查询TX寄存器是否为0,为0表示发送完毕,非0表示还在发送,需要等待发送完毕
}

发送字符串:

void uart0_send_buffer(unsigned char *p, unsigned int len)
{
	int i = 0;

	for (i = 0; i < len; ++i)
	{
		uart0_send_char(*p++);	
	}
}

数据接收

首先需要打开中断

中断模式(INTMOD)寄存器

中断屏蔽(INTMSK)寄存器

次级源挂起(SUBSRCPND)寄存器

中断次级屏蔽(INTSUBMSK)寄存器

对于接收放需要打开INT_RXD0

中断偏移(INTOFFSET)寄存器

接收到的数据要从接收缓存区读取

UART 接收缓冲寄存器(保持寄存器和 FIFO 寄存器)

void uart0_init(void)
{
	unsigned int t;

	//将GPIO端口设置为串口
	GPHCON |= (2 << 4) | (2 << 6);

	//设置串口线路控制寄存器
	t = ULCON0;
	t &= ~(1 << 6);
	t &= ~(7 << 3);
	t &= ~(1 << 2);
	t |= (3 << 0);
	ULCON0 = t;

	//设置控制寄存器
	t = UCON0;
	t &= ~(3 << 10);
	t &= ~((1 << 8) | (1 << 7) | (1 << 6) | (1 << 5) | (1 << 4));
	t |= (1 << 2) | (1 << 0);
	UCON0 = t;
	
	//设置波特率
	UBRDIV0 = 325;

	//设置中断
	INTMOD &= ~(1 << 28);
	INTMSK &= ~(1 << 28);
	INTSUBMSK &= ~(1 << 0);
}
unsigned char rcvBuffer[256];
unsigned int pos;

void uart0_handle(void)
{
	if ((SUBSRCPND & (1 << 0)) != 0)
	{
		rcvBuffer[pos++] = URXH0;	
	}
	SUBSRCPND = SUBSRCPND;
}

main.c

int main(void)
{	
	wdt_init();
	clock_init();
	led_init();
	uart0_init();	

	pos = 0;
	while (1)
	{
		if (pos != 0)
		{
			delay(0x3FFFF);
			uart0_send_buffer(rcvBuffer, pos);
			pos = 0;
		}
	}
}