我要成为嵌入式高手之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;
}
}
}