中级会员
 
- 积分
- 222
- 金钱
- 222
- 注册时间
- 2012-3-15
- 在线时间
- 13 小时
|

楼主 |
发表于 2013-5-13 17:28:37
|
显示全部楼层
#include "sys.h"
#include "delay.h"
#include "usart.h"
#include "stdarg.h"
#include "stdio.h"
#include "string.h"
//如果使用ucos,则包括下面的头文件即可.
#if SYSTEM_SUPPORT_UCOS
#include "includes.h"//ucos 使用
#endif
/*************************************************************************
V1.3修改说明
支持适应不同频率下的串口波特率设置.
加入了对printf的支持
增加了串口接收命令功能.
修正了printf第一个字符丢失的bug
V1.4修改说明
1,修改串口初始化IO的bug
2,修改了USART_RX_STA,使得串口最大接收字节数为2的14次方
3,增加了USART_REC_LEN,用于定义串口最大允许接收的字节数(不大于2的14次方)
4,修改了EN_USART1_RX的使能方式
V1.5修改说明
1,增加了对UCOSII的支持
**************************************************************************/
//加入以下代码,支持printf函数,而不需要选择use MicroLIB
#if 1
#pragma import(__use_no_semihosting)
//标准库需要的支持函数
struct __FILE
{
int handle;
/* Whatever you require here. If the only file you are using is */
/* standard output using printf() for debugging, no file handling */
/* is required. */
};
/* FILE is typedef’ d in stdio.h. */
FILE __stdout;
//定义_sys_exit()以避免使用半主机模式
_sys_exit(int x)
{
x = x;
}
//重定义fputc函数
int fputc(int ch, FILE *f)
{
while((USART1 -> SR & 0X40) == 0);//循环发送,直到发送完毕
USART1->DR = (u8) ch;
return ch;
}
#endif
#if EN_USART1_RX //如果使能了接收
//串口1中断服务程序
//注意,读取USARTx->SR能避免莫名其妙的错误
u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.
//接收状态
//bit15, 接收完成标志
//bit14, 接收到0x0d
//bit13~0, 接收到的有效字节数目
u16 USART_RX_STA = 0; //接收状态标记
void USART1_IRQHandler(void)
{
u8 res;
#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.
OSIntEnter();
#endif
if(USART1->SR & (1 << 5))//接收到数据
{
res = USART1->DR;
if((USART_RX_STA & 0x8000) == 0)//接收未完成
{
if(USART_RX_STA & 0x4000)//接收到了0x0d
{
if(res != 0x0a)USART_RX_STA = 0;//接收错误,重新开始
else USART_RX_STA |= 0x8000; //接收完成了
}else //还没收到0X0D
{
if(res == 0x0d)USART_RX_STA |= 0x4000;
else
{
USART_RX_BUF[USART_RX_STA&0X3FFF] = res;
USART_RX_STA++;
if(USART_RX_STA > (USART_REC_LEN - 1))USART_RX_STA = 0;//接收数据错误,重新开始接收
}
}
}
}
#ifdef OS_CRITICAL_METHOD //如果OS_CRITICAL_METHOD定义了,说明使用ucosII了.
OSIntExit();
#endif
}
#endif
//初始化IO 串口1
//pclk2 CLK2时钟频率(Mhz)
//bound:波特率
//CHECK OK
//091209
void uart_init(u32 pclk2, u32 bound)
{
float temp;
u16 mantissa;
u16 fraction;
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 &= 0XFFFFF00F;//IO状态设置
GPIOA->CRH |= 0X000008B0;//IO状态设置
RCC->APB2RSTR |= 1 << 14; //复位串口1
RCC->APB2RSTR &= ~(1 << 14);//停止复位
//波特率设置
USART1->BRR = mantissa; // 波特率设置
USART1->CR1 |= 0X200C; //1位停止,无校验位.
#if EN_USART1_RX //如果使能了接收
//使能接收中断
USART1->CR1 |= 1 << 8; //PE中断使能
USART1->CR1 |= 1 << 5; //接收缓冲区非空中断使能
MY_NVIC_Init(3, 3, USART1_IRQChannel, 2);//组2,最低优先级
#endif
}
///////////////////////////////串口2///////////////////////////////////////////////////
void TIM4_Set(u8 sta);
void TIM4_Init(u16 arr,u16 psc);
void UART_DMA_Config(DMA_Channel_TypeDef*DMA_CHx,u32 cpar,u32 cmar);
void UART_DMA_Enable(DMA_Channel_TypeDef*DMA_CHx,u8 len);
//串口发送缓存区
__align(8) u8 USART2_TX_BUF[USART2_MAX_SEND_LEN]; //发送缓冲,最大USART2_MAX_SEND_LEN字节
#ifdef USART2_RX_EN //如果使能了接收
//串口接收缓存区
u8 USART2_RX_BUF[USART2_MAX_RECV_LEN]; //接收缓冲,最大USART2_MAX_RECV_LEN个字节.
//通过判断接收连续2个字符之间的时间差不大于10ms来决定是不是一次连续的数据.
//如果2个字符接收间隔超过10ms,则认为不是1次连续数据.也就是超过10ms没有接收到
//任何数据,则表示此次接收完毕.
//接收到的数据状态
//[15]:0,没有接收到数据;1,接收到了一批数据.
//[14:0]:接收到的数据长度
u16 USART2_RX_STA = 0;
void USART2_IRQHandler(void)
{
u8 res;
if(USART2->SR & (1 << 5))//接收到数据
{
res = USART2->DR;
if(USART2_RX_STA < USART2_MAX_RECV_LEN) //还可以接收数据
{
TIM4->CNT = 0; //计数器清空
if(USART2_RX_STA == 0)TIM4_Set(1); //使能定时器4的中断
USART2_RX_BUF[USART2_RX_STA++] = res; //记录接收到的值
}else
{
USART2_RX_STA |= 1 << 15; //强制标记接收完成
}
}
}
//初始化IO 串口2
//pclk1 CLK1时钟频率(Mhz)
//bound:波特率
void USART2_Init(u32 pclk1,u32 bound)
{
RCC->APB2ENR |= 1 << 2; //使能PORTA口时钟
GPIOA->CRL &= 0XFFFF00FF; //IO状态设置
GPIOA->CRL |= 0X00008B00; //IO状态设置
RCC->APB1ENR |= 1 << 17; //使能串口时钟
RCC->APB1RSTR |= 1 << 17; //复位串口2
RCC->APB1RSTR &= ~(1 << 17);//停止复位
//波特率设置
USART2->BRR=(pclk1 * 1000000) / (bound);// 波特率设置
USART2->CR1 |= 0X200C; //1位停止,无校验位.
USART2->CR3 = 1 << 7; //使能串口2的DMA发送
UART_DMA_Config(DMA1_Channel7,(u32) & USART2->DR, (u32)USART2_TX_BUF);//DMA1通道7,外设为串口2,存储器为USART2_TX_BUF
#ifdef USART2_RX_EN //如果使能了接收
//使能接收中断
USART2->CR1 |= 1 << 8; //PE中断使能
USART2->CR1 |= 1 << 5; //接收缓冲区非空中断使能
MY_NVIC_Init(2, 3, USART2_IRQChannel, 2);//组2,最低优先级
TIM4_Init(99, 7199); //10ms中断
USART2_RX_STA = 0; //清零
TIM4_Set(0); //关闭定时器4
#endif
}
//串口2,printf 函数
//确保一次发送数据不超过USART2_MAX_SEND_LEN字节
void u2_printf(char* fmt, ...)
{
va_list ap;
va_start(ap, fmt);
vsprintf((char*)USART2_TX_BUF, fmt, ap);
va_end(ap);
while(DMA1_Channel7->CNDTR != 0); //等待通道7传输完成
UART_DMA_Enable(DMA1_Channel7, strlen((const char*)USART2_TX_BUF)); //通过dma发送出去
}
//定时器4中断服务程序
void TIM4_IRQHandler(void)
{
if(TIM4->SR & 0X01)//是更新中断
{
USART2_RX_STA |= 1 << 15; //标记接收完成
TIM4->SR &= ~(1 << 0); //清除中断标志位
TIM4_Set(0); //关闭TIM4
}
}
//设置TIM4的开关
//sta:0,关闭;1,开启;
void TIM4_Set(u8 sta)
{
if(sta)
{
TIM4->CNT = 0; //计数器清空
TIM4->CR1 |= 1 << 0; //使能定时器4
}else TIM4->CR1 &= ~(1 << 0);//关闭定时器4
}
//通用定时器中断初始化
//这里始终选择为APB1的2倍,而APB1为36M
//arr:自动重装值。
//psc:时钟预分频数
void TIM4_Init(u16 arr, u16 psc)
{
RCC->APB1ENR |= 1 << 2; //TIM4时钟使能
TIM4->ARR = arr; //设定计数器自动重装值
TIM4-> SC = psc; //预分频器
TIM4->DIER |= 1 << 0; //允许更新中断
TIM4->CR1 |= 0x01; //使能定时器4
MY_NVIC_Init(1, 3, TIM4_IRQChannel, 2);//抢占2,子优先级3,组2 在2中优先级最低
}
#endif
///////////////////////////////////////USART2 DMA发送配置部分//////////////////////////////////
//DMA1的各通道配置
//这里的传输形式是固定的,这点要根据不同的情况来修改
//从存储器->外设模式/8位数据宽度/存储器增量模式
//DMA_CHx MA通道CHx
//cpar:外设地址
//cmar:存储器地址
void UART_DMA_Config(DMA_Channel_TypeDef * DMA_CHx, u32 cpar, u32 cmar)
{
RCC->AHBENR |= 1 << 0; //开启DMA1时钟
delay_us(5);
DMA_CHx->CPAR = cpar; //DMA1 外设地址
DMA_CHx->CMAR = cmar; //DMA1,存储器地址
DMA_CHx->CCR = 0X00000000; //复位
DMA_CHx->CCR |= 1 << 4; //从存储器读
DMA_CHx->CCR |= 0 << 5; //普通模式
DMA_CHx->CCR |= 0 << 6; //外设地址非增量模式
DMA_CHx->CCR |= 1 << 7; //存储器增量模式
DMA_CHx->CCR |= 0 << 8; //外设数据宽度为8位
DMA_CHx->CCR |= 0 << 10; //存储器数据宽度8位
DMA_CHx->CCR |= 1 << 12; //中等优先级
DMA_CHx->CCR |= 0 << 14; //非存储器到存储器模式
}
//开启一次DMA传输
void UART_DMA_Enable(DMA_Channel_TypeDef * DMA_CHx, u8 len)
{
DMA_CHx->CCR &= ~(1 << 0); //关闭DMA传输
DMA_CHx->CNDTR = len; //DMA1,传输数据量
DMA_CHx->CCR |= 1 << 0; //开启DMA传输
}
/////////////////////////////////////////////////////////////////////////////////////////////////////////////////////
---------------
#ifndef __USART_H__
#define __USART_H__
#include "sys.h"
#include "stdio.h"
/************************************************************************
V1.3修改说明
支持适应不同频率下的串口波特率设置.
加入了对printf的支持
增加了串口接收命令功能.
修正了printf第一个字符丢失的bug
V1.4修改说明
1,修改串口初始化IO的bug
2,修改了USART_RX_STA,使得串口最大接收字节数为2的14次方
3,增加了USART_REC_LEN,用于定义串口最大允许接收的字节数(不大于2的14次方)
4,修改了EN_USART1_RX的使能方式
V1.5修改说明
1,增加了对UCOSII的支持
***************************************************************************/
#define USART_REC_LEN 512 //定义最大接收字节数 512
#define EN_USART1_RX 1 //使能:1; 禁止0.串口1接收
//////////////////////////////////////串口2//////////////////////////////////////////////////////
#define USART2_MAX_RECV_LEN 200 //最大接收缓存字节数
#define USART2_MAX_SEND_LEN 200 //最大发送缓存字节数
#define USART2_RX_EN 1 //0,不接收;1,接收.
extern u8 USART2_RX_BUF[USART2_MAX_RECV_LEN]; //接收缓冲,最大USART2_MAX_RECV_LEN字节
extern u8 USART2_TX_BUF[USART2_MAX_SEND_LEN]; //发送缓冲,最大USART2_MAX_SEND_LEN字节
extern u16 USART2_RX_STA; //接收数据状态
/////////////////////////////////////////////////////////////////////////////////////////////////
//////////////////////////////////////串口2//////////////////////////////////////////////////////
void USART2_Init(u32 pclk2,u32 bound);
void USART2_Send_Data(u8 *buf,u8 len);
void USART2_Receive_Data(u8 *buf,u8 *len);
void u2_printf(char* fmt,...);
/////////////////////////////////////////////////////////////////////////////////////////////////
extern u8 USART_RX_BUF[USART_REC_LEN]; //接收缓冲,最大USART_REC_LEN个字节.末字节为换行符
extern u16 USART_RX_STA; //接收状态标记
//如果想串口中断接收,请不要注释以下宏定义
void uart_init(u32 pclk2, u32 bound);
#endif |
|