本实验要完成的内容是:通过UART接口将分秒位显示在PC机上,并且通过键盘设置分秒位。应该看到1234567890123...效果。
PA_9和PA_10分别作为输出和输入脚即TX1和RX1。如图是连接图:
主函数如下:
// 定义定时器寄存器地址
#define SysTick_CTRL (*(volatile unsigned long *) (0xE000E010))
#define SysTick_LOAD (*(volatile unsigned long *) (0xE000E014)) //就是STRVR
// 定义时钟允许寄存器地址
#define RCC_APB2ENR (*(volatile unsigned long *) (0x40021018))
// 定义GPIOA寄存器地址
#define GPIOA_CRH (*(volatile unsigned long *) (0x40010804))
// 定义USART1寄存器地址
#define USART1_BRR (*(volatile unsigned long *) (0x40013808))
#define USART1_CR1 (*(volatile unsigned long *) (0x4001380c))
#define USART1_SR (*(volatile unsigned long *) (0x40013800))
#define USART1_DR (*(volatile unsigned long *) (0x40013804))
#include
// 声明函数
void SysTick_Init(void);
void SysTick_Handler(void);
void Usart1_Init(void);
void Txd_Sec(void);
void Rxd_Sec(void);
int Usart1_Txd(int data);
int Usart1_Rxd(void);
int fputc(int ch, FILE *f);
// 声明全局变量
int sec = 0, sec1 = 0,min=0,min1=0,num=0;
// 主函数
int main(void)
{
SysTick_Init(); // 初始化系统定时器
Usart1_Init(); // 初始化USART1
while(1)
{
SysTick_Handler(); // 定时处理
Txd_Sec();
Rxd_Sec(); //发送个位(一秒一次)
}
}
// 系统定时器初始化子程序
void SysTick_Init(void)
{
SysTick_LOAD = 1000000; // 1s定时值(时钟源频率为8MHz/8),每记一次数是1ms,故1,000,000次为1s
SysTick_CTRL = 1; // 启动定时器,SysTick_CTRL为控制寄存器
}
// 定时处理子程序
void SysTick_Handler(void)
{
if(SysTick_CTRL & 0x10000) //1s时间到,SysTick_CTRL的16位为计数标志位,当systick计到0时,该位被置1,
{
if((++sec & 0xf) >= 0xa) sec += 6; // 2-10 进制调整
if(sec >= 0x60)
{sec = 0; // 60s 时间到,复位为0
if((++min & 0xf) >= 0xa) min += 6; // 2-10 进制调整
if(min >= 0x60) min = 0;
} // 60s 时间到,复位为0
}
}
// UART1 初始化子程序
void Usart1_Init(void)
{
RCC_APB2ENR |= 0x4004; // 开启USART1 和GPIOA 时钟 ,2位与14位分别是端口A和USART1的时钟使能位
GPIOA_CRH &= 0xffffff0f;
GPIOA_CRH |= 0x000000b0; // PA.09(TX1)复用推挽输出、仅对PA.09操作,未对PA.10操作,它是默认状态,PA.10(RX1)浮空输入
//GPIOA_CRH ^= 0x000000f0; // 复位状态下效果和以上2 条语句相同
USART1_BRR = 0x0045; // 8000000/115200=69(0x45) 设置波特率为115200
USART1_CR1 = 0x200C; // UART 允许、发送和接收允许,允许中断
//(8位数据、无校验、1 位停止)
}
// USART1 发送子程序
// 入口参数:data-发送数据
// 出口参数:返回发送数据
int Usart1_Txd(int data)
{
while(!(USART1_SR & 0x80)); // 等待TXE=1(发送数据寄存器TDR空,已经被转移到发送移位寄存器)
return(USART1_DR = data); // 发送并返回数据
}
// USART1 接收子程序
// 出口参数:接收数据(接收成功)/0(接收不成功)
int Usart1_Rxd(void)
{
if(USART1_SR & 0x20) // RXNE=1(接收数据寄存器RDR不空,数据已经收到)
return USART1_DR; // 返回接收数据
else
return 0; // 否则返回0
}
// USART 发送sec 个位子程序(1s 发送1 次)
void Txd_Sec(void)
{
if(sec != sec1) // 1s 时间到
{
sec1 = sec;
// Usart1_Txd((sec & 0x0f) + 0x30); // 发送sec 个位(转化为ASCII 码)
printf("%c%c%c%c%c",((min & 0xf0)/0x10) + 0x30 ,(min & 0x0f) + 0x30,0x3a,((sec & 0xf0)/0x10) + 0x30 ,(sec & 0x0f) + 0x30);
//if(!(sec&0xf)) // sec 个位为0
printf("%c", 0xd); // 发送回车
printf("%c", 0xa); // 发送换行
}
}
// USART 设置sec 个位子程序
void Rxd_Sec(void)
{ int data,d[4];
data= Usart1_Rxd();
if(data)
{d[num]=data;
num++;
data=0;
switch(num)
{
case 1:min = (min & 0x0f) + (d[0] - 0x30)*0x10;break;
case 2:min = (min & 0xf0) + (d[1] - 0x30); break;
case 3:sec = (sec & 0x0f) + (d[2] - 0x30)*0x10; break;
case 4:sec = (sec & 0xf0) + (d[3] - 0x30); break;
}
}
}
int fputc(int ch, FILE *f)
{
return(Usart1_Txd(ch)); //向usart写数据
}
这个跟程序比cc2430的那个相对简单,没有显示在lcd屏上,也少了删除的功能。注意不管是接受数据还是发送数据都是以ascII码的形式进行通信,所以当进行设置秒位时,除了输入数字进行设置,还可以输入其他字符,只不过会转成相应的ASCII码值。
UART数据寄存器DR是分成两个部分的,对外虽是一个,但是读、写是对不同的寄存器进行操作,包括TDR和RDR如图:
在显示秒位的时候还可以使用printf函数:
把Usart1_Txd((sec & 0x0f) + 0x30);Usart1_Txd(0xd); Usart1_Txd(0xa); 分别改成
printf("%c", (sec & 0x0f) + 0x30);printf("%c", 0xd); printf("%c", 0xa); 即可
由于printf定义在stdio.h里面,所以要加上这个头文件,还要加上这个fputc函数:
int fputc(int ch, FILE *f)
{
return(Usart1_Txd(ch));
}
因为printf函数默认的输出是显示器输出,如果要在串口或lcd输出必须重新定义相关的函数,比如printf要输出到串口,将fputc里的方向指向串口就可以了。