PIC的還真沒用過,不過從C的角度講 buffer 在沒有初始化的情況下貌似就被使用了,如果編譯器使用固定地址分配給局部變量 buffer 就會出事了。把
桂平網站建設公司成都創新互聯,桂平網站設計制作,有大型網站制作公司豐富經驗。已為桂平上千多家提供企業網站建設服務。企業網站搭建\外貿營銷網站建設要多少錢,請找那個售后服務好的桂平做網站的公司定做!
while(buffer != 'P')
{
buffer = RCREG;
}
改為
do
{
buffer = RCREG;
}
while(buffer != 'P');
可以避免這類BUG;但愿能有點幫助 :)
編程原理
程序1為查詢通信方式接口程序,為一典型的數據采集例程。其中bioscom()函數初始化COM1(此函數實際調用BIOS
INT
14H中斷0號功能)。這樣在程序中就避免了具體設置波特率因子等繁瑣工作,只需直接訪問發送/接收寄存器(3F8H)和線路狀態寄存
這是我以前寫的一個串口通訊文件,全部貼出來了,希望對你有幫助,包括設置,發送,接受數據,你可以好好看看,祝你成功
// 串口Dlg.cpp : 實現文件
//
#include "stdafx.h"
#include "串口.h"
#include "串口Dlg.h"
#include "afxdialogex.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#endif
// 用于應用程序“關于”菜單項的 CAboutDlg 對話框
class CAboutDlg : public CDialogEx
{
public:
CAboutDlg();
// 對話框數據
enum { IDD = IDD_ABOUTBOX };
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV 支持
// 實現
protected:
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialogEx(CAboutDlg::IDD)
{
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialogEx)
END_MESSAGE_MAP()
// C串口Dlg 對話框
C串口Dlg::C串口Dlg(CWnd* pParent /*=NULL*/)
: CDialogEx(C串口Dlg::IDD, pParent)
, m_Selection(0)
, m_recv(_T(""))
, m_send(_T(""))
{
m_hIcon = AfxGetApp()-LoadIcon(IDR_MAINFRAME);
}
void C串口Dlg::DoDataExchange(CDataExchange* pDX)
{
CDialogEx::DoDataExchange(pDX);
DDX_Control(pDX, IDC_MSCOMM1, m_CMscomm);
DDX_Control(pDX, IDC_COMBO2, m_CComboBox);
DDX_Text(pDX, IDC_RECV, m_recv);
DDX_Text(pDX, IDC_SEND, m_send);
}
BEGIN_MESSAGE_MAP(C串口Dlg, CDialogEx)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1, C串口Dlg::OnBnClickedButton1)
ON_CBN_SELCHANGE(IDC_COMBO2, C串口Dlg::OnSelchangeCombo2)
ON_WM_LBUTTONDBLCLK()
ON_BN_CLICKED(IDC_BUTTON2, C串口Dlg::OnBnClickedButton2)
ON_WM_DRAWITEM()
END_MESSAGE_MAP()
// C串口Dlg 消息處理程序
BOOL C串口Dlg::OnInitDialog()
{
CDialogEx::OnInitDialog();
// 將“關于...”菜單項添加到系統菜單中。
// IDM_ABOUTBOX 必須在系統命令范圍內。
ASSERT((IDM_ABOUTBOX 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
BOOL bNameValid;
CString strAboutMenu;
bNameValid = strAboutMenu.LoadString(IDS_ABOUTBOX);
ASSERT(bNameValid);
if (!strAboutMenu.IsEmpty())
{
pSysMenu-AppendMenu(MF_SEPARATOR);
pSysMenu-AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// 設置此對話框的圖標。當應用程序主窗口不是對話框時,框架將自動
// 執行此操作
SetIcon(m_hIcon, TRUE); // 設置大圖標
SetIcon(m_hIcon, FALSE); // 設置小圖標
// TODO: 在此添加額外的初始化代碼
m_CMscomm.put_CommPort(2);
if(m_CMscomm.get_PortOpen())
m_CMscomm.put_PortOpen(0);//解除占用
m_CMscomm.put_PortOpen(1);//打開串口
static CString str("9600,n,8,1");
m_CMscomm.get_Input();
m_CMscomm.put_RThreshold(1);
m_CMscomm.put_Settings(str);
static char ch[10];
CString str1("com");
for(int i=1;i10;i++)
{
itoa(i,ch,10);
m_CComboBox.AddString(str1+ch);
}
m_CComboBox.SetCurSel(0);
return TRUE; // 除非將焦點設置到控件,否則返回 TRUE
}
void C串口Dlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialogEx::OnSysCommand(nID, lParam);
}
}
// 如果向對話框添加最小化按鈕,則需要下面的代碼
// 來繪制該圖標。對于使用文檔/視圖模型的 MFC 應用程序,
// 這將由框架自動完成。
void C串口Dlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // 用于繪制的設備上下文
SendMessage(WM_ICONERASEBKGND, reinterpret_castWPARAM(dc.GetSafeHdc()), 0);
// 使圖標在工作區矩形中居中
int cxIcon = GetSystemMetrics(SM_CXICON);
int cyIcon = GetSystemMetrics(SM_CYICON);
CRect rect;
GetClientRect(rect);
int x = (rect.Width() - cxIcon + 1) / 2;
int y = (rect.Height() - cyIcon + 1) / 2;
// 繪制圖標
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialogEx::OnPaint();
}
CWindowDC dc(this);
CFont font; //設置字體
CBrush brush;
brush.CreateSolidBrush(255);
font.CreatePointFont(150,_T("華文行楷"));
dc.SelectObject(font);
dc.SelectObject(brush);
//dc.TextOut(250,300,_T("大族激光軟件中心"));
}
//當用戶拖動最小化窗口時系統調用此函數取得光標
//顯示。
HCURSOR C串口Dlg::OnQueryDragIcon()
{
return static_castHCURSOR(m_hIcon);
}
void C串口Dlg::OnBnClickedButton1()
{
static char ch1[10];
CString str("");
if(m_CMscomm.get_PortOpen())
m_CMscomm.put_PortOpen(false);
m_CMscomm.put_CommPort(m_Selection+1);
m_CMscomm.put_PortOpen(m_Selection+1);
str.Format("打開串口%d成功",m_Selection+1);
if(m_CMscomm.get_PortOpen())
{
MessageBox(str);
}
else
{
MessageBox("不能打串口");
}
//MessageBox(ch1);
// TODO: 在此添加控件通知處理程序代碼
}
void C串口Dlg::OnSelchangeCombo2()
{
// TODO: 在此添加控件通知處理程序代碼
//int m_Selection;
m_Selection=m_CComboBox.GetCurSel();
}
void C串口Dlg::OnLButtonDblClk(UINT nFlags, CPoint point)
{
// TODO: 在此添加消息處理程序代碼和/或調用默認值
/*short m_short=m_CMscomm.get_CommPort();
CString str;
str.Format(_T("當前打開端口:%d"),m_short+1);
MessageBox(str);
CDialogEx::OnLButtonDblClk(nFlags, point);*/
}
BEGIN_EVENTSINK_MAP(C串口Dlg, CDialogEx)
ON_EVENT(C串口Dlg, IDC_MSCOMM1, 1, C串口Dlg::OnCommMscomm1, VTS_NONE)
END_EVENTSINK_MAP()
void C串口Dlg::OnCommMscomm1()
{
VARIANT variant_inp;
COleSafeArray safearray_inp;
LONG len,k;
BYTE rxdata[2048]; //設置BYTE數組 An 8-bit integerthat is not signed.
CString strtemp; if(m_CMscomm.get_CommEvent()==2) //事件值為2表示接收緩沖區內有字符
{ ////////以下你可以根據自己的通信協議加入處理代碼
variant_inp=m_CMscomm.get_Input(); //讀緩沖區
safearray_inp=variant_inp; //VARIANT型變量轉換為ColeSafeArray型變量
len=safearray_inp.GetOneDimSize(); //得到有效數據長度
for(k=0;klen;k++) safearray_inp.GetElement(k,rxdata+k);//轉換為BYTE型數組
for(k=0;klen;k++) //將數組轉換為Cstring型變量
{ BYTE bt=*(char*)(rxdata+k); //字符型
strtemp.Format("%c",bt); //將字符送入臨時變量strtemp存放
m_send+=strtemp; //加入接收編輯框對應字符串
}
}
UpdateData(FALSE);
}
void C串口Dlg::OnBnClickedButton2()
{
UpdateData();
m_CMscomm.put_Output((COleVariant) m_send);
SetWindowLong(m_hWnd,GWL_EXSTYLE,GetWindowLong(m_hWnd,GWL_EXSTYLE) | WS_EX_ACCEPTFILES);
}
void C串口Dlg::OnDrawItem(int nIDCtl, LPDRAWITEMSTRUCT lpDrawItemStruct)
{
// TODO: 在此添加消息處理程序代碼和/或調用默認值
MessageBox("sfsfe");
CDialogEx::OnDrawItem(nIDCtl, lpDrawItemStruct);
}
我寫的串口通信代碼比較長,給幾個關鍵函數你吧,可實現PC與單片機的雙工通信
/*串口通訊 單片機晶振:11.0592MHz
T1工作于方式2 波特率=2^smod*fosc/32/12/(256-X)*/
#includecommon.h
void do_uart(void); //串口接收執字符時的操作
/*串口發送字符串 */
void sendstr(uchar *p)
{
while(*p!='\0')
{ SBUF=*p; //待發送的數據寫入緩沖區
while(!TI); //等待發送完成
TI=0; //清零發送標志位
p++; //指針加1
cnt_s++; //發送計數
}
}
/*串口接收中斷函數*/
void int_rec(void) interrupt 4 using 2
{
if(RI) //查詢接收標志位(有數據發送過來時置為1)
{
RI = 0; //接收標志位清零
// sendchar(SBUF);//讓從電腦上傳到單片機的數據,傳回的電腦顯示
do_uart();//對接受到得字符操作
}
}
/*串口初始化*/
void com_init(uint baud)
{
SCON = 0x50; //串口工作方式為1,串行允許接受
TMOD = 0x21; //定時器1工作在方式2 定時器0工作在方式1
//PCON = 0x80; //SMOD = 1; 波特率加倍
TH1=256-fosc/32/12/baud;
TL1=TH1;
ES = 1; //開串口中斷
TR1 = 1; //允許定時器1工作
EA = 1; //開總中斷
}
void sendchar(uchar uart_dat) //串口發送字符函數
{
SBUF = uart_dat; //待發送的數據寫入緩沖區
while(!TI); //等待發送完成
TI = 0; //清零發送標志位
cnt_s++; //發送計數
}
以下是我剛改的程序編譯成功了
請參考
#include"reg51.h"
//定義全局變量
unsigned char data_10[10]={0,0,0,0,0,0,0,0,0,0};
unsigned char Time_50ms,count;
bit flag=0;
bit data_flag=0;
/*********************************************************************************************
函數名:UART串口初始化函數
調 用:UART_init();
參 數:無
返回值:無
結 果:啟動UART串口接收中斷,允許串口接收,啟動T/C1產生波特率(占用)
備 注:振蕩晶體為12MHz,PC串口端設置 [ 4800,8,無,1,無 ]
/**********************************************************************************************/
void UART_init (void){
EA = 1; //允許總中斷(如不使用中斷,可用//屏蔽)
ES = 1; //允許UART串口的中斷
TMOD |= 0x20;//定時器T/C1工作方式2
SCON = 0x50;//串口工作方式1,允許串口接收(SCON = 0x40 時禁止串口接收)
TH1 = 0xF3;//定時器初值高8位設置
TL1 = 0xF3;//定時器初值低8位設置
PCON = 0x80;//波特率倍頻(屏蔽本句波特率為2400)
TR1 = 1;//定時器啟動
}
/**********************************************************************************************/
/*********************************************************************************************
函數名:UART串口接收中斷處理函數
調 用:[SBUF收到數據后中斷處理]
參 數:無
返回值:無
結 果:UART串口接收到數據時產生中斷,用戶對數據進行處理(并發送回去)
備 注:過長的處理程序會影響后面數據的接收
/**********************************************************************************************/
void UART_R (void) interrupt 4 using 1{ //切換寄存器組到1
TR0=1; //打開定時器開始計時
RI = 0;//令接收中斷標志位為0(軟件清零)
data_10[count] = SBUF;//將接收到的數據送入變量 UART_data
count++;//接收到一個字節數據計數+1
if(count=10) //如果接收到10個數據
{
TR0=0; //停止定時器
TH0 = 0x3C; //給定時器賦初值
TL0 = 0xB0; //給定時器賦初值
count=0;//清零數據計數
//data_flag=1; //數據有效標志位
SBUF = 0x55;//返回數據 55H
while(TI == 0);//檢查發送中斷標志位
TI = 0;//令發送中斷標志位為0(軟件清零)
}
if(flag)
{
TR0=0; //停止定時器
TH0 = 0x3C; //給定時器賦初值
TL0 = 0xB0; //給定時器賦初值
count=0;//清零數據計數
SBUF = 0xff;//返回數據 ffH
while(TI == 0);//檢查發送中斷標志位
TI = 0;//令發送中斷標志位為0(軟件清零)
}
}
/**********************************************************************************************/
/*********************************************************************************************
函數名:定時/計數器初始化函數
調 用:T_C_init();
參 數:無
返回值:無
結 果:設置SFR中T/C1和(或)T/C0相關參數
備 注:本函數控制T/C1和T/C0,不需要使用的部分可用//屏蔽
/**********************************************************************************************/
void T_C_init (void){
TMOD |= 0x01; //高4位控制T/C1 [ GATE,C/T,M1,M0,GATE,C/T,M1,M0 ]
EA = 1;//中斷總開關
TH0 = 0x3C; //16位計數寄存器T0高8位
TL0 = 0xB0; //16位計數寄存器T0低8位(0x3CB0 = 50mS延時)
ET0 = 1; //T/C0中斷開關
TR0 = 0; //T/C0開關
}
/**********************************************************************************************/
/*********************************************************************************************
函數名:定時/計數器0中斷處理函數
調 用:[T/C0溢出后中斷處理]
參 數:無
返回值:無
結 果:重新寫入16位計數寄存器初始值,處理用戶程序
備 注:必須允許中斷并啟動T/C本函數方可有效,重新寫入初值需和T_C_init函數一致
/**********************************************************************************************/
void T_C0 (void) interrupt 1 using 1{ //切換寄存器組到1
TH0 = 0x3C; //16位計數寄存器T0高8位(重新寫入初值)
TL0 = 0xB0; //16位計數寄存器T0低8位(0x3CB0 = 50mS延時)
Time_50ms++; //50ms到 計數+1
if(Time_50ms=100)
{
Time_50ms=0;// 清零50ms計數
flag=1; //5s時間 標志置位
TR0=0;//關閉計時器
}
}
/**********************************************************************************************/
main()
{
IP = 0x10; //中斷優先級設置(串口中斷最高優先級)
UART_init();//初始化串口
T_C_init(); // 初始化計數器
while(1);// 空循環
}
網頁名稱:一個串口通訊的c語言函數 C語言寫的串口通信
網站網址:http://vcdvsql.cn/article2/hhhdoc.html
成都網站建設公司_創新互聯,為您提供全網營銷推廣、品牌網站設計、定制網站、響應式網站、網頁設計公司、建站公司
聲明:本網站發布的內容(圖片、視頻和文字)以用戶投稿、用戶轉載內容為主,如果涉及侵權請盡快告知,我們將會在第一時間刪除。文章觀點不代表本網站立場,如需處理請聯系客服。電話:028-86922220;郵箱:631063699@qq.com。內容未經允許不得轉載,或轉載時需注明來源: 創新互聯