本帖最后由 小桥流水不 于 2026-3-18 18:33 编辑
使用stc15f2k48s2单片机,485接收温湿度和风速,如果把Task1_Run里的// if (currentTime - lastWindTime >= 1000)// {
// lastWindTime = currentTime;
// ModbusMasterSendWindData();
// windStep = 1;
// windStartTime = currentTime;
// printf("发送风速请求...\n");
// }
}屏蔽,能收到温湿度数据,如果不屏蔽,只能收到风速和风力数据
这是代码:
#include "config.h"
#include "timer.h"
#include "USART.h"
#include "delay.h"
#include "stdio.h"
#include "GPIO.h"
#include "modbus_send_receive.h"
#include "modbus_crc.h"
#include "lcd12864.h"
#include "task_1.h"
/************* 功能说明 **************
双串口全双工中断方式收发通讯程序。
串口1使用串口通讯,串口2使用RS485通讯
通过PC向MCU发送数据, MCU收到后通过串口把收到的数据通过原路返回.
两个串口同时使用定时器2做为波特率发生器,两个串口的波特率相同,如果需要不同波特率,
需改变串口1配置定时器,串口2固定使用定时器2做为波特率发生器
串口1波特率:9600
串口2波特率:9600
开机lcd12864第一行显示“风速测量”
第二行显示风速:和风速值
第三行显示风力:和风力等级
采用rs485和风速传感器通讯,主机发送 01 03 00 00 00 02 C4 0B
“01”代表仪表地址。修改此地址可以和不同地址的仪表通信。
“03”modbus.功能码,使用03“0000” 仪表内部存器地址(即0x0000+0x01)
“0002”代表一次读取2组数据
“C40B”CRC校验,计算得到
此指令的意思是“用功能码03读取仪表地址为01的内部寄存器地址01(即0x00+0x01)开始的2个单位的数据”
从机回复:01 03 04 00 02 00 01 9A 33
说明:
“01”代表仪表地址
“03”代表modbus功能码
“04”代表后面4字节为对应仪表参数“0002”表示当前风速0x02=2,即0.02米/秒(默认2位小数点)
收到回复后将数值解析显示在LCD12864上,也通过串口1打印到pc上
rs485采用串口2,波特率9600,串口发送接收控制引脚 :P12 在USART.h定义
******************************************/
xdata unsigned char str1[] = {"风速:"};
xdata unsigned char str2[] = {"风力: 级"};
xdata unsigned char str3[] = {"温度: "};
xdata unsigned char str4[] = {"℃"};
xdata unsigned char str5[] = {"湿度:"};
xdata unsigned char str6[] = {" %"};
void main(void)
{
u8 i;
Timer_config();
UART_config();
GPIO_config();
Lcd12864_Init();
EA = 1;
Task1_Init();
printf("Init is finish\n");
while (1)
{
Task1_Run();
delay_ms(1);
// if(COM1.RX_TimeOut > 0) //超时计数
// {
// if(--COM1.RX_TimeOut == 0)
// {
// if(COM1.RX_Cnt > 0)
// {
// for(i=0; i<COM1.RX_Cnt; i++)
// {
// TX1_write2buff(RX1_Buffer); //收到的数据通过串口1发送
// }
// }
// COM1.RX_Cnt = 0;
// }
// }
}
}
#include "task_1.h"
#include "lcd12864.h"
#include "delay.h"
#include "modbus_send_receive.h"
#include "stdio.h"
#include "timer.h"
#include "USART.h"
/**
* @brief 风速显示函数
*/
void WindSpeed_Display(u16 speed, u8 row, u8 position)
{
xdata unsigned char digit[4] = {0};
u8 lcd_row = row;
// 边界值处理:超过3690显示无效
if(speed > 3690)
{
Lcd12864_SetPos(lcd_row, position);
Lcd12864_WriteDat('-');
Lcd12864_WriteDat('.');
Lcd12864_WriteDat('-');
Lcd12864_WriteDat('-');
Lcd12864_WriteDat(' ');
Lcd12864_WriteDat('m');
Lcd12864_WriteDat('/');
Lcd12864_WriteDat('s');
return;
}
// 拆分四位数字(千/百/十/个)
digit[0] = (speed / 1000) % 10;
digit[1] = (speed / 100) % 10;
digit[2] = (speed / 10) % 10;
digit[3] = speed % 10;
// 设置显示位置
Lcd12864_SetPos(lcd_row, position);
// 显示整数部分(处理前导0)
if(digit[0] == 0 && digit[1] == 0)
{
Lcd12864_WriteDat('0');
}
else
{
if(digit[0] != 0)
{
Lcd12864_WriteDat(digit[0] + '0');
}
Lcd12864_WriteDat(digit[1] + '0');
}
// 小数点+小数部分
Lcd12864_WriteDat('.');
Lcd12864_WriteDat(digit[2] + '0');
Lcd12864_WriteDat(digit[3] + '0');
// 单位
Lcd12864_WriteDat(' ');
Lcd12864_WriteDat('m');
Lcd12864_WriteDat('/');
Lcd12864_WriteDat('s');
}
/**
* @brief 风级显示函数
*/
void WindLevel_Display(u16 level, u8 row, u8 position)
{
xdata unsigned char digit[2] = {0};
u8 lcd_row = row;
// 风级边界处理(0~12级)
if(level > 12)
{
Lcd12864_SetPos(lcd_row, position);
Lcd12864_WriteDat('-');
Lcd12864_WriteDat('-');
return;
}
// 拆分风级数字
digit[0] = (level / 10) % 10; // 十位
digit[1] = level % 10; // 个位
Lcd12864_SetPos(lcd_row, position);
// 显示风级(处理前导0)
if(digit[0] == 0)
{
Lcd12864_WriteDat(' '); // 十位为0时显示空格
}
else
{
Lcd12864_WriteDat(digit[0] + '0');
}
Lcd12864_WriteDat(digit[1] + '0');
}
/**
* @brief 温度显示函数
*/
void Temperature_Display(int temp_value, u8 row, u8 position)
{
u8 digit[3];
u8 neg_flag = 0;
if (temp_value < 0)
{
neg_flag = 1;
temp_value = -temp_value;
}
digit[0] = (temp_value / 100) % 10;
digit[1] = (temp_value / 10) % 10;
digit[2] = temp_value % 10;
Lcd12864_SetPos(row, position);
if (neg_flag)
Lcd12864_WriteDat('-');
else
Lcd12864_WriteDat(' ');
if (digit[0] == 0)
Lcd12864_WriteDat(' ');
else
Lcd12864_WriteDat(digit[0] + '0');
Lcd12864_WriteDat(digit[1] + '0');
Lcd12864_WriteDat('.');
Lcd12864_WriteDat(digit[2] + '0');
}
/**
* @brief 湿度显示函数
*/
void Humidity_Display(u16 humi_value, u8 row, u8 position)
{
u8 digit[3];
digit[0] = (humi_value / 100) % 10;
digit[1] = (humi_value / 10) % 10;
digit[2] = humi_value % 10;
Lcd12864_SetPos(row, position);
if (digit[0] == 0)
Lcd12864_WriteDat(' ');
else
Lcd12864_WriteDat(digit[0] + '0');
Lcd12864_WriteDat(digit[1] + '0');
Lcd12864_WriteDat('.');
Lcd12864_WriteDat(digit[2] + '0');
}
/**
* @brief 任务1初始化
*/
void Task1_Init(void)
{
Lcd12864_WriteCmd(0x01); // 清屏
delay_ms(20);
// 显示静态文本
Lcd12864_SetPos(1, 1); Lcd12864_WriteCN(str1);
Lcd12864_SetPos(2, 1); Lcd12864_WriteCN(str2);
Lcd12864_SetPos(3, 1); Lcd12864_WriteCN(str3);
Lcd12864_SetPos(3, 7); Lcd12864_WriteCN(str4); // "C"
Lcd12864_SetPos(4, 1); Lcd12864_WriteCN(str5);
Lcd12864_SetPos(4, 6); Lcd12864_WriteCN(str6); // "%"
// 初始显示0值
WindSpeed_Display(0, 1, 4);
WindLevel_Display(0, 2, 4);
Temperature_Display(0, 3, 4);
Humidity_Display(0, 4, 4);
Modbus_ClearBuffer();
printf("Task1初始化完成\n");
}
/**
* @brief 任务1运行 - 修正版(双独立状态机)
*/
void Task1_Run(void)
{
static u32 lastWindTime = 0;
static u32 lastTempTime = 0;
static u16 lastWindSpeed = 0;
static u16 lastWindLevel = 0;
static int lastTemp = 0;
static u16 lastHumi = 0;
// 风速独立状态
static u8 windStep = 0; // 0:空闲, 1:等待响应
static u32 windStartTime = 0;
// 温湿度独立状态
static u8 tempStep = 0; // 0:空闲, 1:等待响应
static u32 tempStartTime = 0;
u32 currentTime = GetSysTimeMs();
// ========== 风速处理(独立) ==========
if (windStep == 0)
{
// 空闲状态,检查是否需要发送
if (currentTime - lastWindTime >= 1000)
{
lastWindTime = currentTime;
ModbusMasterSendWindData();
windStep = 1;
windStartTime = currentTime;
printf("发送风速请求...\n");
}
}
else if (windStep == 1)
{
// 等待风速响应
ModbusMasterReceiveWind();
// 超时处理(500ms)
if (currentTime - windStartTime > 500)
{
printf("风速响应超时\n");
windStep = 0;
COM2.RX_Cnt = 0;
}
// 接收完成
else if (COM2.RX_TimeOut == 0 && COM2.RX_Cnt == 0)
{
windStep = 0;
}
}
// ========== 温湿度处理(独立) ==========
if (tempStep == 0)
{
// 空闲状态,检查是否需要发送
if (currentTime - lastTempTime >= 3000)
{
lastTempTime = currentTime;
ModbusMasterSendTempHumiData();
tempStep = 1;
tempStartTime = currentTime;
printf("发送温湿度请求...\n");
}
}
else if (tempStep == 1)
{
// 等待温湿度响应
ModbusMasterReceiveTempHumi();
// 超时处理(500ms)
if (currentTime - tempStartTime > 500)
{
printf("温湿度响应超时\n");
tempStep = 0;
COM2.RX_Cnt = 0;
}
// 接收完成
else if (COM2.RX_TimeOut == 0 && COM2.RX_Cnt == 0)
{
tempStep = 0;
}
}
// 心跳灯
if (currentTime % 500 < 50)
{
P00 = 0;
}
else
{
P00 = 1;
}
// 更新LCD显示(仅在数据变化时)
if (windSpeed != lastWindSpeed || windLevel != lastWindLevel)
{
WindSpeed_Display(windSpeed, 1, 4);
WindLevel_Display(windLevel, 2, 4);
printf("LCD更新 - 风速:%u(%.2f) 风级:%u\n",
windSpeed, windSpeed*0.01f, windLevel);
lastWindSpeed = windSpeed;
lastWindLevel = windLevel;
}
if (temp != lastTemp || humi != lastHumi)
{
Temperature_Display(temp, 3, 4);
Humidity_Display(humi, 4, 4);
printf("LCD更新 - 温度:%d.%d℃ 湿度:%u.%u%%\n",
temp/10, (temp<0 ? -(temp%10) : temp%10),
humi/10, humi%10);
lastTemp = temp;
lastHumi = humi;
}
}
#ifndef __TASK_1_H
#define __TASK_1_H
#include "config.h"
// 字符串声明
extern xdata unsigned char str1[];
extern xdata unsigned char str2[];
extern xdata unsigned char str3[];
extern xdata unsigned char str4[];
extern xdata unsigned char str5[];
extern xdata unsigned char str6[];
// 函数声明
void Task1_Init(void);
void Task1_Run(void);
void WindSpeed_Display(u16 speed, u8 row, u8 position);
void WindLevel_Display(u16 level, u8 row, u8 position);
void Temperature_Display(int temp_value, u8 row, u8 position);
void Humidity_Display(u16 humi_value, u8 row, u8 position);
#endif
#include "string.h"
#include "modbus_send_receive.h"
#include "timer.h"
#include "stdio.h"
#include "delay.h"
#include "USART.h"
#include "modbus_crc.h"
#include "GPIO.h"
// 全局变量定义
u32 sendFreTime = 0;
u8 xdata sendBuf[8] = {0};
u8 xdata receiveBuf[9] = {0};
u8 xdata temp_humi_buf[9] = {0}; // 温湿度专用接收缓冲区
u16 windSpeed = 0;
u16 windLevel = 0;
int temp = 0; // 温度,有符号整数
u16 humi = 0; // 湿度,无符号整数
/**
* @brief 清除接收缓冲区
*/
void Modbus_ClearBuffer(void)
{
COM2.RX_Cnt = 0;
COM2.RX_TimeOut = 0;
memset(receiveBuf, 0, sizeof(receiveBuf));
memset(temp_humi_buf, 0, sizeof(temp_humi_buf));
}
/**
* @brief 组装风速读取指令(地址0x01)
*/
void ModbusMasterSetWindCmd(void)
{
u16 crc;
sendBuf[0] = SLAVE_ADDR_WIND; // 从机地址 0x01
sendBuf[1] = FUNC_READ_HOLD_REGS; // 功能码 0x03
sendBuf[2] = 0x00; // 寄存器起始地址高字节
sendBuf[3] = REG_ADDR_START; // 寄存器起始地址低字节 0x00
sendBuf[4] = 0x00; // 寄存器数量高字节
sendBuf[5] = REG_COUNT_READ; // 寄存器数量低字节 0x02
crc = ModbusCRC16(sendBuf, 6);
sendBuf[6] = (u8)(crc & 0xFF); // CRC低字节
sendBuf[7] = (u8)(crc >> 8); // CRC高字节
}
/**
* @brief 发送风速读取指令
*/
void ModbusMasterSendWindData(void)
{
u8 i = 0;
ModbusMasterSetWindCmd();
printf("\n发送风速指令: ");
for (i = 0; i < 8; i++)
{
TX2_write2buff(sendBuf);
printf("%bx ", sendBuf);
}
printf("\n");
}
/**
* @brief 接收并解析风速/风级
*/
void ModbusMasterReceiveWind(void)
{
u16 crc_calc;
u8 len;
u8 i;
if (COM2.RX_TimeOut == 0)
{
printf("风速超时,无数据\n");
return;
}
if (--COM2.RX_TimeOut == 0)
{
if (COM2.RX_Cnt > 0)
{
len = COM2.RX_Cnt;
printf("风速原始数据(%d): ", len);
for(i=0; i<len; i++)
{
printf("%bx ", RX2_Buffer);
}
printf("\n");
// 检查长度
if (len != 9)
{
printf("风速长度错误: %d, 期望9\n", len);
COM2.RX_Cnt = 0;
return;
}
// 复制数据
for(i=0; i<9; i++) receiveBuf = RX2_Buffer;
// 打印解析的数据
printf("解析: 地址=%bx, 功能码=%bx, 长度=%bx, ",
receiveBuf[0], receiveBuf[1], receiveBuf[2]);
printf("数据=%bx%bx %bx%bx, CRC=%bx%bx\n",
receiveBuf[3], receiveBuf[4], receiveBuf[5], receiveBuf[6],
receiveBuf[7], receiveBuf[8]);
// 地址校验
if(receiveBuf[0] != SLAVE_ADDR_WIND)
{
printf("风速地址错误: 期望%bx, 收到%bx\n",
SLAVE_ADDR_WIND, receiveBuf[0]);
COM2.RX_Cnt = 0;
return;
}
// 功能码校验
if(receiveBuf[1] != FUNC_READ_HOLD_REGS)
{
printf("风速功能码错误\n");
COM2.RX_Cnt = 0;
return;
}
// CRC校验
crc_calc = ModbusCRC16(receiveBuf, 7);
if(receiveBuf[7] == (u8)(crc_calc & 0xFF) &&
receiveBuf[8] == (u8)(crc_calc >> 8))
{
windSpeed = (u16)receiveBuf[3] << 8 | receiveBuf[4];
windLevel = (u16)receiveBuf[5] << 8 | receiveBuf[6];
printf("风速解析成功: %u (%.2f m/s), 风级: %u\n",
windSpeed, windSpeed * 0.01f, windLevel);
}
else
{
printf("风速CRC错误: 计算=%u, 收到=%bx%bx\n",
crc_calc, receiveBuf[8], receiveBuf[7]);
}
COM2.RX_Cnt = 0;
}
else
{
printf("风速接收缓冲区为空\n");
}
}
}
/**
* @brief 组装温湿度读取指令(地址0x02)
*/
void ModbusMasterSetTempHumiCmd(void)
{
u16 crc;
sendBuf[0] = SLAVE_ADDR_TEMP_HUMI; // 从机地址 0x02
sendBuf[1] = FUNC_READ_HOLD_REGS; // 功能码 0x03
sendBuf[2] = 0x00; // 寄存器起始地址高字节
sendBuf[3] = REG_ADDR_START; // 寄存器起始地址低字节 0x00
sendBuf[4] = 0x00; // 寄存器数量高字节
sendBuf[5] = REG_COUNT_READ; // 寄存器数量低字节 0x02
crc = ModbusCRC16(sendBuf, 6);
sendBuf[6] = (u8)(crc & 0xFF); // CRC低字节
sendBuf[7] = (u8)(crc >> 8); // CRC高字节
}
/**
* @brief 发送温湿度读取指令
*/
void ModbusMasterSendTempHumiData(void)
{
u8 i = 0;
ModbusMasterSetTempHumiCmd();
printf("\n发送温湿度指令: ");
for (i = 0; i < 8; i++)
{
TX2_write2buff(sendBuf);
printf("%bX ", sendBuf);
}
printf("\n");
}
/**
* @brief 接收并解析温湿度
*/
void ModbusMasterReceiveTempHumi(void)
{
u16 crc_calc;
u8 len;
u8 i;
u16 raw_temp;
if (COM2.RX_TimeOut == 0) return;
if (--COM2.RX_TimeOut == 0)
{
if (COM2.RX_Cnt > 0)
{
len = COM2.RX_Cnt;
memcpy(temp_humi_buf, RX2_Buffer, len);
printf("收到温湿度数据(%d字节): ", len);
for( i=0; i<len; i++) printf("%bX ", temp_humi_buf);
printf("\n");
// 校验数据长度
if (len != 9)
{
printf("温湿度长度错误: %d, 期望9字节\n", len);
COM2.RX_Cnt = 0;
return;
}
// 地址和功能码校验
if (temp_humi_buf[0] != SLAVE_ADDR_TEMP_HUMI ||
temp_humi_buf[1] != FUNC_READ_HOLD_REGS)
{
printf("温湿度地址/功能码错误: Addr=0x%bX, Func=0x%bX\n",
temp_humi_buf[0], temp_humi_buf[1]);
COM2.RX_Cnt = 0;
return;
}
// 数据长度校验
if (temp_humi_buf[2] != 0x04)
{
printf("温湿度数据长度错误: 0x%bX\n", temp_humi_buf[2]);
COM2.RX_Cnt = 0;
return;
}
// CRC校验
crc_calc = ModbusCRC16(temp_humi_buf, 7);
if (temp_humi_buf[7] == (u8)(crc_calc & 0xFF) &&
temp_humi_buf[8] == (u8)(crc_calc >> 8))
{
// 解析数据:前两个字节是湿度,后两个字节是温度
humi = (u16)temp_humi_buf[3] << 8 | temp_humi_buf[4];
raw_temp = (u16)temp_humi_buf[5] << 8 | temp_humi_buf[6];
// 温度可能是带符号的(如果传感器支持负温度)
if (raw_temp > 0x7FFF)
{
temp = (int)(raw_temp - 0x10000);
}
else
{
temp = (int)raw_temp;
}
printf("温湿度解析成功: 湿度=%u.%u%%, 温度=%d.%d℃\n",
humi/10, humi%10,
temp/10, (temp < 0 ? -temp%10 : temp%10));
}
else
{
printf("温湿度CRC错误! 计算: 0x%bX, 收到: 0x%bX%bX\n",
crc_calc, temp_humi_buf[8], temp_humi_buf[7]);
}
COM2.RX_Cnt = 0;
}
}
}
#ifndef __MODBUS_SEND_RECEIVE_H
#define __MODBUS_SEND_RECEIVE_H
#include "config.h"
// 协议相关宏定义
#define SLAVE_ADDR_WIND 0x01 // 风速传感器地址
#define SLAVE_ADDR_TEMP_HUMI 0x02 // 温湿度传感器地址
#define FUNC_READ_HOLD_REGS 0x03 // 读保持寄存器功能码
#define REG_ADDR_START 0x00 // 寄存器起始地址
#define REG_COUNT_READ 0x02 // 要读取的寄存器数量
// ==================== 全局变量声明 ====================
extern u32 sendFreTime; // 串口发送数据间隔
extern u8 xdata sendBuf[8]; // 发送缓冲区
extern u8 xdata receiveBuf[9]; // 风速接收缓冲区
extern u8 xdata temp_humi_buf[9]; // 温湿度接收缓冲区
extern u16 windSpeed; // 风速值 (单位: 0.01 m/s)
extern u16 windLevel; // 风级值
extern int temp; // 温度值 (单位: 0.1℃)
extern u16 humi; // 湿度值 (单位: 0.1%)
// ==================== 函数声明 ====================
/**
* @brief 组装风速读取指令
*/
void ModbusMasterSetWindCmd(void);
/**
* @brief 发送风速读取指令
*/
void ModbusMasterSendWindData(void);
/**
* @brief 接收并解析风速/风级
*/
void ModbusMasterReceiveWind(void);
/**
* @brief 组装温湿度读取指令
*/
void ModbusMasterSetTempHumiCmd(void);
/**
* @brief 发送温湿度读取指令
*/
void ModbusMasterSendTempHumiData(void);
/**
* @brief 接收并解析温湿度
*/
void ModbusMasterReceiveTempHumi(void);
/**
* @brief 清除接收缓冲区
*/
void Modbus_ClearBuffer(void);
#endif
#include "USART.h"
#include "stdio.h"
#include "delay.h"
COMx_Define COM1,COM2;
u8 xdata TX1_Buffer[COM_TX1_Lenth]; //发送缓冲
u8 xdata RX1_Buffer[COM_RX1_Lenth]; //接收缓冲
u8 xdata TX2_Buffer[COM_TX2_Lenth]; //发送缓冲
u8 xdata RX2_Buffer[COM_RX2_Lenth]; //接收缓冲
u8 USART_Configuration(u8 UARTx, COMx_InitDefine *COMx)
{
u8 i;
u32 j;
if(UARTx == USART1)
{
COM1.id = 1;
COM1.TX_read = 0;
COM1.TX_write = 0;
COM1.B_TX_busy = 0;
COM1.RX_Cnt = 0;
COM1.RX_TimeOut = 0;
COM1.B_RX_OK = 0;
for(i=0; i<COM_TX1_Lenth; i++) TX1_Buffer = 0;
for(i=0; i<COM_RX1_Lenth; i++) RX1_Buffer = 0;
if(COMx->UART_Mode > UART_9bit_BRTx) return 2; //模式错误
if(COMx->UART_Polity == PolityHigh) PS = 1; //高优先级中断
else PS = 0; //低优先级中断
SCON = (SCON & 0x3f) | COMx->UART_Mode;
if((COMx->UART_Mode == UART_9bit_BRTx) ||(COMx->UART_Mode == UART_8bit_BRTx)) //可变波特率
{
j = (MAIN_Fosc / 4) / COMx->UART_BaudRate; //按1T计算
if(j >= 65536UL) return 2; //错误
j = 65536UL - j;
if(COMx->UART_BRT_Use == BRT_Timer1)
{
TR1 = 0;
AUXR &= ~0x01; //S1 BRT Use Timer1;
TMOD &= ~(1<<6); //Timer1 set As Timer
TMOD &= ~0x30; //Timer1_16bitAutoReload;
AUXR |= (1<<6); //Timer1 set as 1T mode
TH1 = (u8)(j>>8);
TL1 = (u8)j;
ET1 = 0; //禁止中断
TMOD &= ~0x40; //定时
INT_CLKO &= ~0x02; //不输出时钟
TR1 = 1;
}
else if(COMx->UART_BRT_Use == BRT_Timer2)
{
AUXR &= ~(1<<4); //Timer stop
AUXR |= 0x01; //S1 BRT Use Timer2;
AUXR &= ~(1<<3); //Timer2 set As Timer
AUXR |= (1<<2); //Timer2 set as 1T mode
TH2 = (u8)(j>>8);
TL2 = (u8)j;
IE2 &= ~(1<<2); //禁止中断
AUXR &= ~(1<<3); //定时
AUXR |= (1<<4); //Timer run enable
}
else return 2; //错误
}
else if(COMx->UART_Mode == UART_ShiftRight)
{
if(COMx->BaudRateDouble == ENABLE) AUXR |= (1<<5); //固定波特率SysClk/2
else AUXR &= ~(1<<5); //固定波特率SysClk/12
}
else if(COMx->UART_Mode == UART_9bit) //固定波特率SysClk*2^SMOD/64
{
if(COMx->BaudRateDouble == ENABLE) PCON |= (1<<7); //固定波特率SysClk/32
else PCON &= ~(1<<7); //固定波特率SysClk/64
}
if(COMx->UART_Interrupt == ENABLE) ES = 1; //允许中断
else ES = 0; //禁止中断
if(COMx->UART_RxEnable == ENABLE) REN = 1; //允许接收
else REN = 0; //禁止接收
P_SW1 = (P_SW1 & 0x3f) | (COMx->UART_P_SW & 0xc0); //切换IO
if(COMx->UART_RXD_TXD_Short == ENABLE) PCON2 |= (1<<4); //内部短路RXD与TXD, 做中继, ENABLE,DISABLE
else PCON2 &= ~(1<<4);
return 0;
}
if(UARTx == USART2)
{
COM2.id = 2;
COM2.TX_read = 0;
COM2.TX_write = 0;
COM2.B_TX_busy = 0;
COM2.RX_Cnt = 0;
COM2.RX_TimeOut = 0;
COM2.B_RX_OK = 0;
for(i=0; i<COM_TX2_Lenth; i++) TX2_Buffer = 0;
for(i=0; i<COM_RX2_Lenth; i++) RX2_Buffer = 0;
if((COMx->UART_Mode == UART_9bit_BRTx) ||(COMx->UART_Mode == UART_8bit_BRTx)) //可变波特率
{
if(COMx->UART_Polity == PolityHigh) IP2 |= 1; //高优先级中断
else IP2 &= ~1; //低优先级中断
if(COMx->UART_Mode == UART_9bit_BRTx) S2CON |= (1<<7); //9bit
else S2CON &= ~(1<<7); //8bit
j = (MAIN_Fosc / 4) / COMx->UART_BaudRate; //按1T计算
if(j >= 65536UL) return 2; //错误
j = 65536UL - j;
AUXR &= ~(1<<4); //Timer stop
AUXR &= ~(1<<3); //Timer2 set As Timer
AUXR |= (1<<2); //Timer2 set as 1T mode
TH2 = (u8)(j>>8);
TL2 = (u8)j;
IE2 &= ~(1<<2); //禁止中断
AUXR |= (1<<4); //Timer run enable
}
else return 2; //模式错误
if(COMx->UART_Interrupt == ENABLE) IE2 |= 1; //允许中断
else IE2 &= ~1; //禁止中断
if(COMx->UART_RxEnable == ENABLE) S2CON |= (1<<4); //允许接收
else S2CON &= ~(1<<4); //禁止接收
P_SW2 = (P_SW2 & ~1) | (COMx->UART_P_SW & 0x01); //切换IO
}
}
/*************** 装载串口发送缓冲 *******************************/
void TX1_write2buff(u8 dat) //写入发送缓冲,指针+1
{
TX1_Buffer[COM1.TX_write] = dat; //装发送缓冲
if(++COM1.TX_write >= COM_TX1_Lenth) COM1.TX_write = 0;
if(COM1.B_TX_busy == 0) //空闲
{
COM1.B_TX_busy = 1; //标志忙
TI = 1; //触发发送中断
}
}
void TX2_write2buff(u8 dat) //写入发送缓冲,指针+1
{
// 关键修改:只在发送第一个字节时切换485方向
if (COM2.B_TX_busy == 0) // 空闲状态,即将开始发送
{
RS485_DIR_PIN = RS485_TX_MODE; // 切到发送模式
delay_us(200); // 重要!延时等待485芯片切换完成(200微秒)
}
TX2_Buffer[COM2.TX_write] = dat;
if(++COM2.TX_write >= COM_TX2_Lenth) COM2.TX_write = 0;
if(COM2.B_TX_busy == 0) //空闲
{
COM2.B_TX_busy = 1; //标志忙
SET_TI2(); //触发发送中断
}
}
void PrintString1(u8 *puts)
{
for (; *puts != 0; puts++) TX1_write2buff(*puts); //遇到停止符0结束
}
void PrintString2(u8 *puts)
{
for (; *puts != 0; puts++) TX2_write2buff(*puts); //遇到停止符0结束
}
/*
void COMx_write2buff(COMx_Define *COMx, u8 dat) //写入发送缓冲,指针+1
{
if(COMx->id == 1) TX1_write2buff(dat);
if(COMx->id == 2) TX2_write2buff(dat);
}
void PrintString(COMx_Define *COMx, u8 *puts)
{
for (; *puts != 0; puts++) COMx_write2buff(COMx,*puts); //遇到停止符0结束
}
*/
/********************* UART1中断函数************************/
void UART1_int (void) interrupt UART1_VECTOR
{
if(RI)
{
RI = 0;
if(COM1.B_RX_OK == 0)
{
if(COM1.RX_Cnt >= COM_RX1_Lenth) COM1.RX_Cnt = 0;
RX1_Buffer[COM1.RX_Cnt++] = SBUF;
COM1.RX_TimeOut = TimeOutSet1;
}
}
if(TI)
{
TI = 0;
if(COM1.TX_read != COM1.TX_write)
{
SBUF = TX1_Buffer[COM1.TX_read];
if(++COM1.TX_read >= COM_TX1_Lenth) COM1.TX_read = 0;
}
else COM1.B_TX_busy = 0;
}
}
/********************* UART2中断函数************************/
void UART2_int (void) interrupt UART2_VECTOR
{
if(RI2) // 接收中断
{
CLR_RI2();
// 收到数据时,强制切回接收模式(确保模式正确)
RS485_DIR_PIN = RS485_RX_MODE;
if(COM2.B_RX_OK == 0)
{
if(COM2.RX_Cnt < COM_RX2_Lenth) // 防止缓冲区溢出
{
RX2_Buffer[COM2.RX_Cnt++] = S2BUF;
COM2.RX_TimeOut = TimeOutSet2;
}
else
{
// 缓冲区满,清空
COM2.RX_Cnt = 0;
RX2_Buffer[COM2.RX_Cnt++] = S2BUF;
COM2.RX_TimeOut = TimeOutSet2;
}
}
}
if(TI2) // 发送中断
{
CLR_TI2();
if(COM2.TX_read != COM2.TX_write)
{
// 还有数据要发送
S2BUF = TX2_Buffer[COM2.TX_read];
if(++COM2.TX_read >= COM_TX2_Lenth) COM2.TX_read = 0;
}
else
{
// 所有数据发送完毕
COM2.B_TX_busy = 0;
// 关键修改:延时等待最后1字节发送完成
// 波特率9600时,1字节约1.04ms,延时1.5ms确保安全
delay_ms(2); // 2ms延时,确保最后1字节完全发出
// 切换回接收模式
RS485_DIR_PIN = RS485_RX_MODE;
}
}
}
char putchar(char c)
{
if(c == '\n')
{
TX1_write2buff('\r');
}
TX1_write2buff((u8)c); // 对接硬件串口的发送缓冲,触发中断发送
return c; // 按C51标准要求返回,无实际意义
}
#ifndef __USART_H
#define __USART_H
#include "config.h"
// ********* 485方向控制定义 *********
#define RS485_DIR_PIN P12 // 485 DE/RE控制引脚(根据你的硬件修改)
#define RS485_TX_MODE 1 // 发送模式:DE=1, RE=1
#define RS485_RX_MODE 0 // 接收模式:DE=0, RE=0
#define COM_TX1_Lenth 128
#define COM_RX1_Lenth 128
#define COM_TX2_Lenth 128
#define COM_RX2_Lenth 128
#define USART1 1
#define USART2 2
#define UART_ShiftRight 0 //同步移位输出
#define UART_8bit_BRTx (1<<6) //8位数据,可变波特率
#define UART_9bit (2<<6) //9位数据,固定波特率
#define UART_9bit_BRTx (3<<6) //9位数据,可变波特率
#define UART1_SW_P30_P31 0
#define UART1_SW_P36_P37 (1<<6)
#define UART1_SW_P16_P17 (2<<6) //必须使用内部时钟
#define UART2_SW_P10_P11 0
#define UART2_SW_P46_P47 1
#define TimeOutSet1 5
#define TimeOutSet2 5
#define BRT_Timer1 1
#define BRT_Timer2 2
typedef struct
{
u8 id; //串口号
u8 TX_read; //发送读指针
u8 TX_write; //发送写指针
u8 B_TX_busy; //忙标志
u8 RX_Cnt; //接收字节计数
u8 RX_TimeOut; //接收超时
u8 B_RX_OK; //接收块完成
} COMx_Define;
typedef struct
{
u8 UART_Mode; //模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
u8 UART_BRT_Use; //使用波特率, BRT_Timer1,BRT_Timer2
u32 UART_BaudRate; //波特率, ENABLE,DISABLE
u8 Morecommunicate; //多机通讯允许, ENABLE,DISABLE
u8 UART_RxEnable; //允许接收, ENABLE,DISABLE
u8 BaudRateDouble; //波特率加倍, ENABLE,DISABLE
u8 UART_Interrupt; //中断控制, ENABLE,DISABLE
u8 UART_Polity; //优先级, PolityLow,PolityHigh
u8 UART_P_SW; //切换端口, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17(必须使用内部时钟)
u8 UART_RXD_TXD_Short; //内部短路RXD与TXD, 做中继, ENABLE,DISABLE
} COMx_InitDefine;
extern COMx_Define COM1,COM2;
extern u8 xdata TX1_Buffer[COM_TX1_Lenth]; //发送缓冲
extern u8 xdata RX1_Buffer[COM_RX1_Lenth]; //接收缓冲
extern u8 xdata TX2_Buffer[COM_TX2_Lenth]; //发送缓冲
extern u8 xdata RX2_Buffer[COM_RX2_Lenth]; //接收缓冲
u8 USART_Configuration(u8 UARTx, COMx_InitDefine *COMx);
void TX1_write2buff(u8 dat); //写入发送缓冲,指针+1
void TX2_write2buff(u8 dat); //写入发送缓冲,指针+1
void PrintString1(u8 *puts);
void PrintString2(u8 *puts);
//void COMx_write2buff(COMx_Define *COMx, u8 dat); //写入发送缓冲,指针+1
//void PrintString(COMx_Define *COMx, u8 *puts);
char putchar(char c);
#endif
#include "lcd12864.h"
#include "delay.h"
sbit CS = P3^2; // 串行片选端:1=有效,0=无效 (对应并行输入的RS)
sbit SID = P3^3; // 串行数据端:收发数据 (对应并行输入的RW)
sbit SCK = P3^4; // 串行时钟端:上升沿锁存数据 (对应并行输入的E)
//sbit RST = P3^5; // 硬件复位端:0=复位,1=正常工作 (对应并行输入的RST)
// sbit PSB = P1^3; // 串口模式→硬件必须直接接GND,此引脚无效
/**
***********************************************************
* @brief 串行接收1字节数据(参考代码适配,ST7920标准)
* @return 拼接后的8位有效数据
* @note 连续读2字节,高4位+低4位拼接,适配ST7920串口读数据时序
***********************************************************/
static unsigned char ReceiveByte(void)
{
unsigned char i, temp1, temp2;
temp1 = temp2 = 0;
// 读高4位相关数据
for(i=0; i<8; i++)
{
temp1 = temp1 << 1;
SCK = 0;
SCK = 1;
SCK = 0;
if(SID) temp1++;
}
// 读低4位相关数据
for(i=0; i<8; i++)
{
temp2 = temp2 << 1;
SCK = 0;
SCK = 1;
SCK = 0;
if(SID) temp2++;
}
return ((0xF0 & temp1) + (0x0F & temp2)); // 拼接为8位有效数据
}
/**
***********************************************************
* @brief 串行发送1字节数据(参考代码核心,ST7920标准时序)
* @param dat:要发送的8位字节
* @note
***********************************************************/
static void Lcd_SendByte(unsigned char dat)
{
unsigned char i;
for(i=0; i<8; i++)
{
SCK = 0; // 下降沿准备数据
SID = (dat & 0x80) != 0; // 直接取最高位
dat = dat << 1;
SCK = 1; // 上升沿锁存数据
SCK = 0; // 时钟归0,参考代码标准操作
}
}
/**
***********************************************************
* @brief 检测LCD12864忙信号(参考代码适配,无卡死)
* @note 发0xFC读忙前缀,循环判断bit7,直到LCD空闲
***********************************************************/
void Lcd_12864_BusyCheck()
{
do
{
Lcd_SendByte(0xFC); // 串行读忙前缀:11111 RW(1) RS(0) 0
}while(0x80 & ReceiveByte()); // bit7=1则忙,循环等待
}
/**
***********************************************************
* @brief 向LCD12864写入命令(参考代码核心,ST7920标准)
* @param cmd:要写入的命令字(ST7920指令集)
* @note CS片选→忙检测→发前缀→高4位→低4位→CS失选,严格按手册
***********************************************************/
void Lcd12864_WriteCmd(unsigned char cmd)
{
CS = 1; // 片选有效
Lcd_12864_BusyCheck(); // 忙检测,参考代码逻辑无卡死
Lcd_SendByte(0xF8); // 串行写命令固定前缀:11111 RW(0) RS(0) 0
Lcd_SendByte(0xF0 & cmd); // 发送命令高4位(屏蔽低4位)
Lcd_SendByte(0xF0 & (cmd << 4)); // 发送命令低4位(左移后屏蔽)
CS = 0; // 片选无效,完成命令写入
delay_ms(1); // 短延时,保证指令执行
}
/**
***********************************************************
* @brief 向LCD12864写入数据(参考代码核心,ST7920标准)
* @param dat:要写入的8位数据(汉字双字节/ASCII字符)
* @note 写数据前缀0xFA,其余逻辑与写命令一致
***********************************************************/
void Lcd12864_WriteDat(unsigned char dat)
{
CS = 1; // 片选有效
Lcd_12864_BusyCheck(); // 忙检测
Lcd_SendByte(0xFA); // 串行写数据固定前缀:11111 RW(0) RS(1) 0
Lcd_SendByte(0xF0 & dat); // 发送数据高4位
Lcd_SendByte(0xF0 & (dat << 4)); // 发送数据低4位
CS = 0; // 片选无效
delay_ms(1); // 短延时,保证数据锁存
}
/**
***********************************************************
* @brief LCD12864初始化函数(参考代码标准串口流程,必显!)
* @note 完全对齐参考代码的初始化指令,复位+3次0x30+标准配置
***********************************************************/
void Lcd12864_Init(void)
{
// RST = 0;
// delay_ms(100); // 参考代码用100ms延时,保证硬件复位彻底
// RST = 1;
// delay_ms(100); // 复位后稳定时间
// 参考代码核心:连续3次发0x30,确保ST7920识别并进入基础指令集
Lcd12864_WriteCmd(0x30);
delay_ms(100);
Lcd12864_WriteCmd(0x30);
delay_ms(100);
Lcd12864_WriteCmd(0x30);
delay_ms(100);
// 参考代码标准后续配置,按顺序执行
Lcd12864_WriteCmd(0x03); // 入口模式设置
delay_ms(50);
Lcd12864_WriteCmd(0x01); // 清屏
delay_ms(100);
Lcd12864_WriteCmd(0x06); // 光标移动方向配置
delay_ms(100);
Lcd12864_WriteCmd(0x0C); // 开显示、关光标、关闪烁
delay_ms(100);
}
// 以下2个函数:完全保留你的代码,无任何修改!!!
/**
***********************************************************
* @brief LCD12864显示位置定位函数
* @param x:目标显示行号,有效范围1~4(LCD共4行)
* @param y:目标显示列号,有效范围1~8(中文专属,1汉字占2列)
* @return 无
* @note x/y越界时直接返回,不执行定位;ST7920固定行起始地址映射
***********************************************************
*/
void Lcd12864_SetPos(unsigned char x, unsigned char y)
{
unsigned char pos = 0;
if(x < 1 || x > 4 || y < 1 || y > 8)
{
return;
}
y = y - 1;
switch(x)
{
case 1 : pos = 0x80 + y; break;
case 2 : pos = 0x90 + y; break;
case 3 : pos = 0x88 + y; break;
case 4 : pos = 0x98 + y; break;
default : break;
}
Lcd12864_WriteCmd(pos);
}
/******************************************************************
* @brief LCD12864写入GB2312汉字字符串(数组传参版)
* @param cn:GB2312汉字字符串数组(双字节/汉字)
* @return 无
* @note 1. 调用前必须先调用Lcd12864_SetPos定位显示起始位置
* 2. 自动循环写入,直到检测到字符串结束符'\0'
* 3. 数组传参本质等价于指针
***********************************************************/
void Lcd12864_WriteCN( unsigned char cn[])
{
while(*cn)
{
Lcd12864_WriteDat(*cn ++); // 逐个写入数组元素,指针后移
}
}
#ifndef __LCD12864_H__
#define __LCD12864_H__
#include "config.h"
/**
***********************************************************
* @brief LCD12864初始化函数(串口版)
* @param 无
* @return 无
* @note 纯中文显示适配,仅开启基础指令集,**PSB硬件接GND**
***********************************************************
*/
void Lcd12864_Init(void);
/**
***********************************************************
* @brief 向LCD12864写入命令(串口版)
* @param cmd:要写入的命令字(ST7920指令集,与并口一致)
* @return 无
* @note 写入前自动检测忙信号,确保LCD空闲后再操作
***********************************************************
*/
void Lcd12864_WriteCmd(unsigned char cmd);
/**
***********************************************************
* @brief 向LCD12864写入数据(串口版)
* @param dat:要写入的8位数据(汉字双字节/ASCII字符)
* @return 无
* @note 写入前自动检测忙信号,适配GB2312和ASCII编码
***********************************************************
*/
void Lcd12864_WriteDat(unsigned char dat);
/**
***********************************************************
* @brief LCD12864显示位置定位函数(无修改)
* @param x:目标显示行号,有效范围1~4(LCD共4行)
* @param y:目标显示列号,有效范围1~8(中文专属,1汉字占2列)
* @return 无
* @note x/y越界时直接返回,不执行定位;ST7920固定行起始地址映射
***********************************************************
*/
void Lcd12864_SetPos(unsigned char x, unsigned char y);
/******************************************************************
* @brief LCD12864写入GB2312汉字字符串(数组传参版)
* @param cn:GB2312汉字字符串数组(双字节/汉字)
* @return 无
* @note 1. 调用前必须先调用Lcd12864_SetPos定位显示起始位置
* 2. 自动循环写入,直到检测到字符串结束符'\0'
* 3. 数组传参本质等价于指针
***********************************************************/
void Lcd12864_WriteCN( unsigned char cn[]) ;
#endif
#include "config.h"
#include "USART.h"
#include "GPIO.h"
#include "timer.h"
/******************** IO配置函数 **************************/
void GPIO_config(void)
{
GPIO_InitTypeDef GPIO_InitStructure; //结构定义
// P1口定义 485使能引脚
GPIO_InitStructure.Pin = GPIO_Pin_2; //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作GPIO_Pin_All
GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P1,&GPIO_InitStructure); //初始化
GPIO_InitStructure.Pin = GPIO_Pin_All; //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作GPIO_Pin_All
GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P0,&GPIO_InitStructure); //初始化
//P3口定义 LCD12864
GPIO_InitStructure.Pin = GPIO_Pin_2; //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作
GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P3,&GPIO_InitStructure); //初始化
GPIO_InitStructure.Pin = GPIO_Pin_3; //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作
GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P3,&GPIO_InitStructure); //初始化
GPIO_InitStructure.Pin = GPIO_Pin_4; //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作
GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P3,&GPIO_InitStructure); //初始化
GPIO_InitStructure.Pin = GPIO_Pin_5; //指定要初始化的IO, GPIO_Pin_0 ~ GPIO_Pin_7, 或操作
GPIO_InitStructure.Mode = GPIO_PullUp; //指定IO的输入或输出方式,GPIO_PullUp,GPIO_HighZ,GPIO_OUT_OD,GPIO_OUT_PP
GPIO_Inilize(GPIO_P3,&GPIO_InitStructure); //初始化
}
/************************ 定时器配置 ****************************/
void Timer_config(void)
{
//初值为1000时,为1ms定时器
TIM_InitTypeDef TIM_InitStructure; //结构定义
TIM_InitStructure.TIM_Mode = TIM_16BitAutoReload; //指定工作模式, TIM_16BitAutoReload,TIM_16Bit,TIM_8BitAutoReload,TIM_16BitAutoReloadNoMask
TIM_InitStructure.TIM_Polity = PolityLow; //指定中断优先级, PolityHigh,PolityLow
TIM_InitStructure.TIM_Interrupt = ENABLE; //中断是否允许, ENABLE或DISABLE
TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_1T; //指定时钟源, TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
TIM_InitStructure.TIM_ClkOut = ENABLE; //是否输出高速脉冲, ENABLE或DISABLE
TIM_InitStructure.TIM_Value = 65536UL - (MAIN_Fosc / 1000); //初值, 1/2 = 0.5KHZ = 500HZ
TIM_InitStructure.TIM_Run = ENABLE; //是否初始化后启动定时器, ENABLE或DISABLE
Timer_Inilize(Timer0,&TIM_InitStructure); //初始化Timer0 Timer0,Timer1,Timer2
////初值为1000时,为1ms定时器
// TIM_InitStructure.TIM_Mode = TIM_16BitAutoReload; //指定工作模式, TIM_16BitAutoReload,TIM_16Bit,TIM_8BitAutoReload,TIM_16BitAutoReloadNoMask
// TIM_InitStructure.TIM_Polity = PolityLow; //指定中断优先级, PolityHigh,PolityLow
// TIM_InitStructure.TIM_Interrupt = ENABLE; //中断是否允许, ENABLE或DISABLE
// TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_1T; //指定时钟源, TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
// TIM_InitStructure.TIM_ClkOut = ENABLE; //是否输出高速脉冲, ENABLE或DISABLE
// TIM_InitStructure.TIM_Value = 65536UL - (MAIN_Fosc / 1000); //初值, 1/2 = 0.5KHZ = 500HZ
// TIM_InitStructure.TIM_Run = ENABLE; //是否初始化后启动定时器, ENABLE或DISABLE
// Timer_Inilize(Timer1,&TIM_InitStructure); //初始化Timer1 Timer0,Timer1,Timer2
////初值为50时,为20ms定时器
// TIM_InitStructure.TIM_Interrupt = ENABLE; //中断是否允许, ENABLE或DISABLE. (注意: Timer2固定为16位自动重装, 中断固定为低优先级)
// TIM_InitStructure.TIM_ClkSource = TIM_CLOCK_12T; //指定时钟源, TIM_CLOCK_1T,TIM_CLOCK_12T,TIM_CLOCK_Ext
// TIM_InitStructure.TIM_ClkOut = ENABLE; //是否输出高速脉冲, ENABLE或DISABLE
// TIM_InitStructure.TIM_Value = 65536UL - (MAIN_Fosc / (50*12)); //初值 0.5/2=0.025KHZ = 25HZ
// TIM_InitStructure.TIM_Run = ENABLE; //是否初始化后启动定时器, ENABLE或DISABLE
// Timer_Inilize(Timer2,&TIM_InitStructure); //初始化Timer2 Timer0,Timer1,Timer2
}
/************* 外部函数和变量声明 *****************/
void UART_config(void)
{
COMx_InitDefine COMx_InitStructure; //结构定义
COMx_InitStructure.UART_Mode = UART_8bit_BRTx; //模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
COMx_InitStructure.UART_BRT_Use = BRT_Timer2; //使用波特率, BRT_Timer1, BRT_Timer2 (注意: 串口2固定使用BRT_Timer2)
COMx_InitStructure.UART_BaudRate = 9600ul; //波特率, 一般 110 ~ 115200
COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLE
COMx_InitStructure.BaudRateDouble = DISABLE; //波特率加倍, ENABLE或DISABLE
COMx_InitStructure.UART_Interrupt = ENABLE; //中断允许, ENABLE或DISABLE
COMx_InitStructure.UART_Polity = PolityLow; //中断优先级, PolityLow,PolityHigh
COMx_InitStructure.UART_P_SW = UART1_SW_P30_P31; //切换端口, UART1_SW_P30_P31,UART1_SW_P36_P37,UART1_SW_P16_P17(必须使用内部时钟)
COMx_InitStructure.UART_RXD_TXD_Short = DISABLE; //内部短路RXD与TXD, 做中继, ENABLE,DISABLE
USART_Configuration(USART1, &COMx_InitStructure); //初始化串口1 USART1,USART2
COMx_InitStructure.UART_Mode = UART_8bit_BRTx; //模式, UART_ShiftRight,UART_8bit_BRTx,UART_9bit,UART_9bit_BRTx
COMx_InitStructure.UART_BaudRate = 9600ul; //波特率, 110 ~ 115200
COMx_InitStructure.UART_RxEnable = ENABLE; //接收允许, ENABLE或DISABLE
COMx_InitStructure.UART_Interrupt = ENABLE; //中断允许, ENABLE或DISABLE
COMx_InitStructure.UART_Polity = PolityLow; //中断优先级, PolityLow,PolityHigh
COMx_InitStructure.UART_P_SW = UART2_SW_P10_P11; //切换端口, UART2_SW_P10_P11,UART2_SW_P46_P47
USART_Configuration(USART2, &COMx_InitStructure); //初始化串口2 USART1,USART2
// PrintString1("STC15F2K60S2 UART1 Test Prgramme!\r\n"); //SUART1发送一个字符串
PrintString2("STC15F2K60S2 UART2 Test Prgramme!\r\n"); //SUART2发送一个字符串
}
#ifndef __CONFIG_H
#define __CONFIG_H
/*********************************************************/
#define MAIN_Fosc 22118400L //定义主时钟
//#define MAIN_Fosc 12000000L //定义主时钟
//#define MAIN_Fosc 11059200L //定义主时钟
//#define MAIN_Fosc 5529600L //定义主时钟
//#define MAIN_Fosc 24000000L //定义主时钟
/*********************************************************/
#include "STC15Fxxxx.H"
void UART_config(void);
void GPIO_config(void);
void Timer_config(void);
#endif
|