本帖最后由 小橋流水不 于 2026-3-18 18:33 編輯
使用stc15f2k48s2單片機,485接收溫濕度和風速,如果把Task1_Run里的// if (currentTime - lastWindTime >= 1000)// {
// lastWindTime = currentTime;
// ModbusMasterSendWindData();
// windStep = 1;
// windStartTime = currentTime;
// printf("發送風速請求...\n");
// }
}屏蔽,能收到溫濕度數據,如果不屏蔽,只能收到風速和風力數據
ebd880824a66e78736e301a2a758291f.jpg (3.62 MB, 下載次數: 0)
下載附件
2026-3-18 18:30 上傳
5cc10eb4e213afe7f37d3f5282df37c0.jpg (3.74 MB, 下載次數: 0)
下載附件
2026-3-18 18:29 上傳
這是代碼:
#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
|