⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 uart.c

📁 dspic6012a 实例 6012mcu的串口接收通信实例
💻 C
字号:
//8.3  程序清单

//方法一: 使用回归计算的源代码

#include "p30F6014.h" 		  // 标准头文件
#include "math.h" 			  // 数学库
#define Fcy 29491200		  // 允许波特率计算用于显示

// 函数原型
void SetupAutoBaud(void); 	// 该函数用于设置UART1、IC1 和TMR3
void CalculateBaud(void); 	// 该函数用于计算U1BRG 值

// 变量
unsigned int ICCount = 0; 		// 对捕捉事件次数进行计数
unsigned int T3Count = 0; 		// 对Timer 3 中断数进行计数
unsigned int CurrentCapture; 	// 记录UART 边沿的时间
unsigned int PreviousCapture;	// 存储上一次边沿时间测量值
unsigned int CaptureDifference; // UART 边沿时间差值
long SumXY, SumY; 			// 用于回归计算的立即数
long RegressionData[10]; 	// 用于线性回归的数据
unsigned long BaudRate; 		// 计算波特率

// 主程序
// 无限循环检测UART 输入数据0x55 的波特率
// 并每次在波特率计算完后输出一条报文。
int main(void)
{
	while(1) 							// 无限循环
	{
		SetupAutoBaud(); 				// 为自动波特率检测设置UART1、IC1 及TMR3
		while(U1BRG == 0) {} 			// 等待自动波特率检测结束
		BaudRate = (Fcy / 16) / (U1BRG + 1); // 查看当前使用的波特率
		printf("Baud rate: %ld\r", BaudRate);// 输出带有波特率的文本
		while(U1STAbits.TRMT == 0) {} 	// 等待发送结束
	}
} 										

// 设置外设和中断以进行波特率检测
void SetupAutoBaud(void)
{
	U1BRG = 0; 			// U1BRG 初始值未知
	U1MODE = 0x8020; 	// 使能UART 中的自动波特率检测功能
	U1STA = 0x0000; 	// 将UART 的其他功能设定为缺省状态
	ICCount = 0; 		// 对捕捉事件的次数进行初始化
	IC1CON = 0x0000; 	// 复位输入捕捉1 模块
	IC1CON = 0x0001; 	// 使能输入捕捉1 模块
	IFS0bits.IC1IF = 0; // 清除捕捉模块1 中断标志
	IEC0bits.IC1IE = 1; // 使能捕捉1 中断
	T3CON = 0x0000; 	//Timer 3 关闭
	IEC0bits.T3IE = 0; 	// 清除Timer 3 中断使能
	T3Count = 0; 		// 对Timer 3 的中断数进行初始化
	PR3 = 0xffff; 		//Timer 3 周期为最大值
	T3CON = 0x8000; 	//Timer 3 启用且设置为1:1 预分频比以及内部时钟
}

// 计算U1BRG 波特率发生器的值
void CalculateBaud(void)
{
	int i; 								// 用于进行误差求和的循环变量
	long Slope; 						// 回归计算的斜率(位时间)
	long Yintercept;					// 第一个边沿的期望的(计算的)时间
	long PlotLine; 						// 每一个边沿的期望的(计算的)时间
	long SumOfErrors = 0; 					// 所有误差的和| 测量值- 期望值|
	Slope = (2 * SumXY - 9 * SumY) / 165; 	// 计算斜率 = 一个位时间
	Yintercept = (SumY - Slope * 45) / 10; // 计算第一个边沿的期望时间
	PlotLine = Yintercept; 					// 对每一个边沿的期望时间进行初始化
	for(i=0; i<10; i++) 					// 循环以对所有绝对误差进行累加
	{
		SumOfErrors += abs(RegressionData[i] - PlotLine);// 计算并加上下一个误差
		PlotLine += Slope; 							// 计算下一个边沿的期望时间
	}
	if((SumOfErrors * 2) < Slope) 	// 检查是否平均绝对误差<5%
	{ 							     // (10 个误差值累加和的两倍是否< 一个位时间?)
		U1BRG = ((Slope + 8) >> 4) - 1;	// 计算UxBRG (通过加半位进行舍入)
		U1MODE = 0x8000; 			     // 使能UART 并禁止自动波特率检测
		U1STA = 0x0400; 				// 使能发送
	}
	else
	{
		SetupAutoBaud(); 				// 误差太大因此重新开始
	}
}

// 输入捕捉1中断服务程序(ISR)
// 获得时间测量值并加到回归计算所需的累加和中
void _ISR _IC1Interrupt(void)
{
	IFS0bits.IC1IF = 0; 				// 清除捕捉1 中断标志
	PreviousCapture = CurrentCapture; 	// 存储前一次时间测量值
	CurrentCapture = IC1BUF; 			// 获取新的时间测量值
	T3Count = 0; 						// 复位超时计数器
	if(ICCount == 0) 					// 检查是否为第一个边沿
	{
		IFS0bits.T3IF = 0; 				// 清除Timer 3 中断标志
		IEC0bits.T3IE = 1; 			// 使能Timer 3 中断用于超时检查
		RegressionData[0] = 0; 		// 第一个边沿时间的初始值
		SumY = 0; 					// 时间测量值和的初始值
		SumXY = 0;					// 位数x 时间和的初始值
	}
	Else							//检查是否非第一个边沿
	{
		CaptureDifference = CurrentCapture - PreviousCapture; // 获得时间差
		RegressionData[ICCount]=RegressionData[ICCount-1] + CaptureDifference;
		// 将时间差加到前一次时间测量值中
		SumY += RegressionData[ICCount]; 			// 对时间测量值进行求和
		SumXY += RegressionData[ICCount] * ICCount;// 对位数 x 时间测量值进行求和
	}
	ICCount++; 		   // 对边沿递增计数
	if(ICCount == 10) // 检查是否最后一个边沿
	{
		IEC0bits.IC1IE = 0; 	// 清除捕捉1 中断使能位
		IEC0bits.T3IE = 0; 	     // 清除Timer 3 中断使能位
		CalculateBaud(); 		// 计算U1BRG 值并使能UART
	}
}

//Timer 3 ISR
//检查是否超时,即自前一次输入捕捉是否有两次溢出
void _ISR _T3Interrupt(void)
{
	IFS0bits.T3IF = 0;  // 清除Timer 3 中断标志
	T3Count++; 		     // 自上一次捕捉起的中断递增计数
	if(T3Count == 2) 	// 检查自上一次捕捉起是否发生太多定时器溢出
	{
		SetupAutoBaud(); // 超时因此重新开始
	}
}

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -