《AlientekSTM32例程手册》28个实验连载--串口实验--整理后
[复制链接]
1.注意我们的教材讲解是基于寄存器操作,方便初学者理解透彻,
2.我们另外还提供了该实例的库函数源码, 下载链接:https://bbs.eeworld.com.cn/icview-210815-1-1.html
3.此实验的教程在《Alientek STM32不完全手册》的 3.3节:
下载地址:《Alientek STM32不完全手册》
4.源码:
CLK2时钟频率(Mhz)
//bound:波特率
void uart_init(u32 pclk2,u32bound)
{
floattemp;
u16mantissa;
u16fraction;
temp=(float)(pclk2*1000000)/(bound*16);//得到USARTDIV
mantissa=temp;
//得到整数部分
fraction=(temp-mantissa)*16;//得到小数部分
mantissa<<=4;
mantissa+=fraction;
RCC->APB2ENR|=1<<2;
//使能PORTA口时钟
RCC->APB2ENR|=1<<14;
//使能串口时钟
GPIOA->CRH=0X444444B4;//IO状态设置
RCC->APB2RSTR|=1<<14;
//复位串口1
RCC->APB2RSTR&=~(1<<14);//停止复位
//波特率设置
USART1->BRR=mantissa; // 波特率设置
USART1->CR1|=0X200C;
//1位停止,无校验位.
#ifdef EN_USART1_RX
//如果使能了接收
//使能接收中断
USART1->CR1|=1<<8;
//PE中断使能
USART1->CR1|=1<<5;
//接收缓冲区非空中断使能
MY_NVIC_Init(3,3,USART1_IRQChannel,2);//组2,最低优先级
#endif
}
从该代码可以看出,其初始化串口的过程,和我们前面介绍的一致先计算得到USART1->BRR的内容。然后开始初始化串口引脚,接着把USART1复位,然之后设置波特率和奇偶校验等。
这里需要注意一点,因为我们使用到了串口的中断接收,必须在usart.h里面定义 EN_USART1_RX 。该函数才会配置中断使能,以及开启串口1的NVIC中断。这里我们把串口1中断放在组2,优先级设置为组2里面的最低。
再介绍一下串口1的中断服务函数USART1_IRQHandler,该函数的名字不能自己定义了,MDK已经给每个中断都分配了一个固定的函数名,我们直接用就可以了。具体这些函数的名字是什么,我们可以在MDK提供的例子里面,找到stm32f10x_it.c,该文件里面包含了STM32所有的中断服务函数。USART1_IRQHandler的代码如下:
void USART1_IRQHandler(void)
{
u8res;
if(USART1->SR&(1<<5))//接收到数据
{
res=USART1->DR;
if((USART_RX_STA&0x80)==0)//接收未完成
{
if(USART_RX_STA&0x40)//接收到了0x0d
{
if(res!=0x0a)USART_RX_STA=0;//接收错误,重新开始
elseUSART_RX_STA|=0x80;
//接收完成了
}else //还没收到0X0D
{
if(res==0x0d)USART_RX_STA|=0x40;
else
{
USART_RX_BUF[USART_RX_STA&0X3F]=res;
USART_RX_STA++;
if(USART_RX_STA>63)USART_RX_STA=0;//接收数据错误,重新开始接收
}
}
}
}
}
该函数的重点就是判断接收是否完成,通过检测是否收到0X0D、0X0A的连续2个字节(回车键)来检测是否结束。当检测到这个结束序列之后,就会置位USART_RX_STA的最高为来标记已经收到了一次数据。之后等待外部函数清空该位之后才开始第二次接收。所接收的数据全部存放在USART_RX_BUF里面,一次接收数据不能超过64个字节,否则被丢弃。
介绍完了这两个函数,我们回到test.c,在test.c里面编写如下代码:
#include <stm32f10x_lib.h>
#include "sys.h"
#include "usart.h"
#include "delay.h"
#include "led.h"
#include "key.h"
//Mini STM32开发板范例代码3
//串口实验
//正点原子@ALIENTEK
//2010.5.28
int main(void)
{
u8t;
u8len;
u16times=0;
Stm32_Clock_Init(9);//系统时钟设置
delay_init(72);
//延时初始化
uart_init(72,9600);
//串口初始化为9600
LED_Init();
//初始化与LED连接的硬件接口
while(1)
{
if(USART_RX_STA&0x80)
{
len=USART_RX_STA&0x3f;//得到此次接收到的数据长度
printf("\n您发送的消息为:\n");
for(t=0;t<len;t++)
{
USART1->DR=USART_RX_BUF[t];
while((USART1->SR&0X40)==0);//等待发送结束
}
printf("\n\n");//插入换行
USART_RX_STA=0;
}else
{
times++;
if(times%5000==0)
{
printf("\nMiniSTM32开发板
串口实验\n");
printf("正点原子@ALIENTEK\n\n\n");
}
if(times%200==0)printf("请输入数据,以回车键结束\n");
if(times%30==0)LED0=!LED0;//闪烁LED,提示系统正在运行.
delay_ms(10);
}
}
}
这段代码比较简单,重点看下以下两句:
USART1->DR=USART_RX_BUF[t];
while((USART1->SR&0X40)==0);//等待发送结束
第一句,其实就是发送一个字节到串口,通过直接操作寄存器来实现的。第二句呢,就是我们在写了一个字节在USART1->DR之后,要检测这个数据是否已经被发送完成了,通过检测USART1->SR的第6位,是否为1来决定是否可以开始第二个字节的发送。
可以看到,这里我们的代码比上一节的多了800多字节,其实这里主要是使用了printf函数的缘故,所以如果有时候你程序太大了,可以通过不使用printf函数,来给其他代码腾出一部分空间。
店铺:http://shop62057469.taobao.com/
http://shop62103354.taobao.com/
我们的技术支持论坛:www.openedv.com
QQ讨论群:95288038(验证:21ic)
QQ:389063473/ 497610476
|