分享MSP430F149和PC机串口通信编程实例
[复制链接]
/******************************************************************************
#include "msp430x14x.h" // Standard Equations
typedef unsigned char uchar ;
typedef unsigned int uint ;
/*******************************************
functional module
*******************************************/
void delay_l(int q);
void ClockInit() ; //时钟初始化
void UartInit() ; //串口通信初始化函数
void SendDataToPC(uchar *value) ; //发送数据函数
void SendDataToPC1(uchar value) ;
void ADDataTodecimal(uchar *p,uint value) ; //十六进制转换十进制函数
uchar value[5] ; //用来存放把一个十六进制熟转换为十
uint temp = 0 ; //Function as exchange data
uchar i,j ;
/********************************************
main function
********************************************/
void main(void)
{
WDTCTL = WDTPW+WDTHOLD; // Stop watchdog timer
value[4] = '/0' ; // ADD A END SIGN TO
ClockInit();
UartInit(); //Initial series communication
P6SEL |= 0x10 ; // Enable A/D channel A3
ADC12CTL0 = ADC12ON |REFON |REF2_5V ; // Turn on ADC12, set sampling time
ADC12CTL1 = SHS_1 + SHP + CONSEQ_2 ; // Use sampling timer, set mode
ADC12MCTL0 |= INCH_4 ; //Select input signal from A0 channel
delay_l(6) ;
ADC12CTL0 |= ENC ; // Enable conversions
CCTL0 = CCIE ; //Enable timerA Interrupt
TACCR0 = 4000; //Sample frequence about 1000Hz
TACCR1 = 2000 ;
TACCTL1 = OUTMOD_3 ; //PWM set/reset
TACTL = TASSEL_2 + MC_1 + TACLR ; //Use increase count mode
//TACTL = TASSEL_2 + MC_1 ;
_BIS_SR(LPM0_bits + GIE) ; // Enter LPM0 LOW-POWER0 MODE
}
/********************************************
//Intialized the SMCLK Clock
*********************************************/
void ClockInit()
{
BCSCTL1 &=~ XT2OFF ;
do
{
IFG1 &=~ OFIFG ;
for(uint i=0xff;i>0;i--) ;
}
while((IFG1 & OFIFG));
BCSCTL1 |= SELS | DIVS1 | DIVS0 ;
}
/*******************************************
USART初始化,选择波特率为9600,8位,无校验位
*******************************************/
void UartInit()
{
P3SEL |= 0x30 ; // P3.4,5 = USART0 TXD/RXD
ME1 |= URXE0 + UTXE0 ; // Enable USART0 T/RXD
UCTL0 |= CHAR ; // 8-bit character
UTCTL0 |= SSEL0 ; // UCLK = ACLK
//**Common used baud rates********************/
// UCLK---------Clock----------32k---------ACLK
// UxBR1=0x0,UxBR0=0x1B,UxMCTL=0x03---1200bit/s
UBR10 = 0x00 ; //SET BAUD // UxBR1=0x0,UxBR0=0x0D,UxMCTL=0x6B---2400bit/s
UBR00 = 0x06 ; // UxBR1=0x0,UxBR0=0x06,UxMCTL=0x6F---4800bit/s
UMCTL0 = 0x6f ;//Modulation // UxBR1=0x0,UxBR0=x03,UxMCTL=0x4A---9600bit/s
//************BAUD=2400Bit/s******************/
UCTL0 &= ~SWRST ; // Initialize USART state machine
IE1 |= URXIE0 ; //Open Transmit interrupt
}
/************************************************
定时器A中断服务程序把AD采集的数据放到
results[Num_of_Results]
************************************************/
#pragma vector=TIMERA0_VECTOR //TIMERA0_VECTOR INTERRUPT SERVICE
__interrupt void TIMERAISR (void) //ROUTINE
{
_BIC_SR(LPM0_bits) ;
temp = ADC12MEM0 ; //SAVE THE CONVERSATIN RESULT
ADDataTodecimal(value,temp); //Conversation HEX into DECIMAL
for(j = 0;j <= 3;j++)
{
value[j] += 0x30 ; //Conversation the DECIMAL into
}
SendDataToPC(value); //Transmit a serial of characters
//for(uint k=0x7f;k>0;k--);
} //per time
#pragma vector = UART0RX_VECTOR
__interrupt void receive_ISR(void)
{
_BIC_SR_IRQ(LPM3_bits); // Clear LPM3 bits from 0(SR)
if ( RXBUF0 == 0x31 )
{
UCTL0 |= SWRST;
ME1 &= ~UTXE0;
UCTL0 &= ~SWRST;
}
if ( RXBUF0 == 0x32 )
{
UCTL0 |= SWRST;
ME1 |= URXE0 + UTXE0 ; // Enable USART0 T/RXD
UCTL0 &= ~SWRST;
}
}
/***********************************
功能:发送数据给PC机
参数:*P指向被发送的数据的缓冲区
还回值:无
发送3位数据-----参考下面发送4位程序
***********************************/
void SendDataToPC(uchar *value)
{
while(*value != '/0') //JUDGE A CHARACTER IS END SIGN OR NOT
{
while(!(IFG1 & UTXIFG0)) ;//TRANSMIT COMPLETELY OR NOT
TXBUF0 = *value ;
value++ ;
}
while(!(IFG1 & UTXIFG0)) ;
TXBUF0 = '/n' ;
}
/*****************************/
void SendDataToPC1(uchar value)
{
while(!(IFG1 & UTXIFG0)) ;
TXBUF0 = value ;
while(!(IFG1 & UTXIFG0)) ;
TXBUF0 = '/n' ;
}
/********************************************
函数名称:ADDataTodecimal
功 能:将16进制ADC转换数据变换成十进制
表示形式
参 数:value--16进制数据
p--指向存放转换结果的指针
返回值 :无
********************************************/
void ADDataTodecimal(uchar *p,uint value)
{
p[0] = value / 1000 ; //THE THOUSAND BIT
p[1] = (value - p[0]*1000)/100 ; //THE HUNDRED BIT
p[2] = (value - p[0]*1000 - p[1]*100)/10 ; //THE DECIMAL BIT
p[3] = (value - p[0]*1000 - p[1]*100 - p[2]*10);// THE INDIVIDUAL BIT
}
/*******************************
功能:延时
**************************
void delay_l(int q)
{
int a,b;
for(a=0; a<q; a++ )
for(b=0;b<30000;b++);
}
上面的程序是MSP430F149的采用定时器定时触发A/D转换,并把转换好的数据发送到PC机,
Code:
// FormComDlg.cpp : implementation file
//
#include "stdafx.h"
#include "FormCom.h"
#include "FormComDlg.h"
#include "time.h"
#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif
/////////////////////////////////////////////////////////////////////////////
// CAboutDlg dialog used for App About
//int data[4096];
//#define Num 1000
class CAboutDlg : public CDialog
{
public:
CAboutDlg();
// Dialog Data
//{{AFX_DATA(CAboutDlg)
enum { IDD = IDD_ABOUTBOX };
//}}AFX_DATA
// ClassWizard generated virtual function overrides
//{{AFX_VIRTUAL(CAboutDlg)
protected:
virtual void DoDataExchange(CDataExchange* pDX); // DDX/DDV support
//}}AFX_VIRTUAL
// Implementation
protected:
//{{AFX_MSG(CAboutDlg)
//}}AFX_MSG
DECLARE_MESSAGE_MAP()
};
CAboutDlg::CAboutDlg() : CDialog(CAboutDlg::IDD)
{
//{{AFX_DATA_INIT(CAboutDlg)
//}}AFX_DATA_INIT
}
void CAboutDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CAboutDlg)
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CAboutDlg, CDialog)
//{{AFX_MSG_MAP(CAboutDlg)
// No message handlers
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CFormComDlg dialog
CFormComDlg::CFormComDlg(CWnd* pParent /*=NULL*/)
: CDialog(CFormComDlg::IDD, pParent)
{
//{{AFX_DATA_INIT(CFormComDlg)
m_strReceiveData = _T("");
m_selcom = _T("");
m_selbaud = _T("");
//}}AFX_DATA_INIT
// Note that LoadIcon does not require a subsequent DestroyIcon in Win32
m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME);
}
void CFormComDlg::DoDataExchange(CDataExchange* pDX)
{
CDialog::DoDataExchange(pDX);
//{{AFX_DATA_MAP(CFormComDlg)
DDX_Control(pDX, IDC_COMBO3, m_sendControlInfo);
DDX_Control(pDX, IDC_COMBO2, m_selbuadd);
DDX_Control(pDX, IDC_COMBO1, m_selcomm);
DDX_Control(pDX, IDC_EDIT2, m_ctrReceiveData);
DDX_Control(pDX, IDC_MSCOMM1, m_ctrComm);
DDX_Text(pDX, IDC_EDIT2, m_strReceiveData);
DDX_CBString(pDX, IDC_COMBO1, m_selcom);
DDX_CBString(pDX, IDC_COMBO2, m_selbaud);
//}}AFX_DATA_MAP
}
BEGIN_MESSAGE_MAP(CFormComDlg, CDialog)
//{{AFX_MSG_MAP(CFormComDlg)
ON_WM_SYSCOMMAND()
ON_WM_PAINT()
ON_WM_QUERYDRAGICON()
ON_BN_CLICKED(IDC_BUTTON1_CLEARRECE, OnClearReceiveData)
ON_WM_TIMER()
ON_BN_CLICKED(IDC_SendData, OnSendData)
ON_BN_CLICKED(IDC_BUTTON1, On_CloseSerial)
//}}AFX_MSG_MAP
END_MESSAGE_MAP()
/////////////////////////////////////////////////////////////////////////////
// CFormComDlg message handlers
BOOL CFormComDlg::OnInitDialog()
{
CDialog::OnInitDialog();
// Add "About..." menu item to system menu.
// IDM_ABOUTBOX must be in the system command range.
ASSERT((IDM_ABOUTBOX & 0xFFF0) == IDM_ABOUTBOX);
ASSERT(IDM_ABOUTBOX < 0xF000);
CMenu* pSysMenu = GetSystemMenu(FALSE);
if (pSysMenu != NULL)
{
CString strAboutMenu;
strAboutMenu.LoadString(IDS_ABOUTBOX);
if (!strAboutMenu.IsEmpty())
{
pSysMenu->AppendMenu(MF_SEPARATOR);
pSysMenu->AppendMenu(MF_STRING, IDM_ABOUTBOX, strAboutMenu);
}
}
// Set the icon for this dialog. The framework does this automatically
// when the application's main window is not a dialog
SetIcon(m_hIcon, TRUE); // Set big icon
SetIcon(m_hIcon, FALSE); // Set small icon
// TODO: Add extra initialization here
for(int i=0;i<ECGNum;i++)ECGdata[i]=0;
ecgnum=0;
// if (m_selcomm.GetCurSel()<0)
// i = 2;
// else
// i = m_selcomm.GetCurSel()+1;
m_ctrComm.SetCommPort(2);//选择端口COM2
// if (m_selbuadd.GetCurSel()<0)
// i = 2;
// else
/// i = m_selbuadd.GetCurSel();
//int n=m_selbuadd.GetLBTextLen(i);
// CString str;
// m_selbuadd.GetLBText(i,str);
// str += ",n,8,1";
m_ctrComm.SetInputMode(1);//输入方式为二进制
m_ctrComm.SetInBufferSize(4096);//设置输入缓冲区大小
m_ctrComm.SetOutBufferSize(512);//设置输出缓冲区大小
m_ctrComm.SetSettings("4800,n,8,1");//设置串口4800,N,8,1
if(!m_ctrComm.GetPortOpen())//检测串口是否打开
m_ctrComm.SetPortOpen(true);//打开串口
m_ctrComm.SetRThreshold(1);//参数1表示当串口接收缓冲区中有多于1或者等于1个
//字符将引发一个接收数据的OnCom事件
m_ctrComm.SetInputLen(0);//设置当前接收数据的长度为0
m_ctrComm.GetInput();//先预留缓冲区以清除残留数据
return TRUE; // return TRUE unless you set the focus to a control
}
void CFormComDlg::OnSysCommand(UINT nID, LPARAM lParam)
{
if ((nID & 0xFFF0) == IDM_ABOUTBOX)
{
CAboutDlg dlgAbout;
dlgAbout.DoModal();
}
else
{
CDialog::OnSysCommand(nID, lParam);
}
}
// If you add a minimize button to your dialog, you will need the code below
// to draw the icon. For MFC applications using the document/view model,
// this is automatically done for you by the framework.
void CFormComDlg::OnPaint()
{
if (IsIconic())
{
CPaintDC dc(this); // device context for painting
SendMessage(WM_ICONERASEBKGND, (WPARAM) dc.GetSafeHdc(), 0);
// Center icon in client rectangle
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;
// Draw the icon
dc.DrawIcon(x, y, m_hIcon);
}
else
{
CDialog::OnPaint();
}
}
// The system calls this to obtain the cursor to display while the user drags
// the minimized window.
HCURSOR CFormComDlg::OnQueryDragIcon()
{
return (HCURSOR) m_hIcon;
}
BEGIN_EVENTSINK_MAP(CFormComDlg, CDialog)
//{{AFX_EVENTSINK_MAP(CFormComDlg)
ON_EVENT(CFormComDlg, IDC_MSCOMM1, 1 /* OnComm */, OnComm, VTS_NONE)
//}}AFX_EVENTSINK_MAP
END_EVENTSINK_MAP()
/************************************************************************/
void CFormComDlg::OnComm()
{
//SetTimer(1,100,NULL);
LONG len=0,k=0;//定义从串口发送过来是数据长度
BYTE rxdata[1200];//定义一个存放从串口发送数据的BYTE类型的数组
CString strtemp=_T("0");//定义CString类型的变量实现BYTE类型转换为CString类型
// TODO: Add your control notification handler code here
COleVariant variant_inp;
COleSafeArray safearray_inp;//定义一个COleSafeArray的类型的变量实现串口数据类型与
if(m_ctrComm.GetCommEvent()==2)//判断串口接收缓冲区有没接收到数据
{
variant_inp.Attach(m_ctrComm.GetInput());//把串口缓冲区的数据读到variant_inp结构体中
safearray_inp=variant_inp;
len=safearray_inp.GetOneDimSize();
BOOL flag;
for(k=0;k<len;k++)
safearray_inp.GetElement(&k,rxdata+k);//转换为BYTE数组
for(k=0;k<len;k++)//把BYTE的数组转换为CString
{
BYTE bt=*(char*)(rxdata+k);
strtemp.Format("%c",bt);
m_strReceiveData+=strtemp;//m_strReceiveData用来存储串口接收的所有数据
flag =true;
while(flag)//判断从串口接收的数据是否大于等于5个字节,如果满足这个条件
{
if(m_strReceiveData.GetLength()<5)
flag = false;
else
{
strtemp=m_strReceiveData.Left(4);//取conv字符串中的最左边四个字符,因为我发送过来的数据是5个字节,
//其中最后一个字节是一个‘/n
data[ecgnum]=_ttoi(strtemp);//两种数据的转换
num=(ecgnum+1)%ECGNum;//数组长度加1
m_strReceiveData.Delete(1,5);//删除已经转换的字符串
OnTimer(1);
}
}
strtemp=_T("0");//重新给这个变量进行初始化
}
}
UpdateData(false);
}
void CFormComDlg::OnClearReceiveData()
{
// TODO: Add your control notification handler code here
m_strReceiveData.Empty();//CLEAR THE CONTENT OF m_strReceiveData
for (int i = 0;i<=num-1;i++);
data[i] = 0;
num = 0;
UpdateData(false);//UPDATE THE DRAWING AREA,In principle the aim of this item
}
void CFormComDlg::DrawECG(CDC* pDC)
{
int i=0;
CRect rec;
CWnd* pWnd=GetDlgItem(IDC_STATIC12);//DIRECT TO DRAWING CONTROL
pWnd->GetClientRect(&rec);//DIRECT TO THE CLIENT PICTURE AREA
pDC->Rectangle(&rec);//DIRECTED THE PICTURE AREA
CPen* pPenRed = new CPen;//RED PEN
pPenRed->CreatePen(PS_SOLID,1,RGB(255,0, 0));
CPen* pOldPen=pDC->SelectObject(pPenRed);
int temp = 0;
for(i=0;i<num-1;i++)//pay attention to the consistent with coordinate between two point
{
pDC->MoveTo(rec.left+temp,data[i]/10-30);
pDC->LineTo(rec.left+1+temp,data[i+1]/10-30);
if(rec.left+1+temp>rec.Width()-10)
{
temp = 0;
}
else
temp = temp + 1;
}
pDC->SelectObject(pOldPen);
pWnd->ReleaseDC(pDC);
delete pPenRed;
}
/**********************************************************
/**********************************************************/
void CFormComDlg::OnTimer(UINT nIDEvent)
{
// TODO: Add your message handler code here and/or call default
CRect rect;
CWnd* pWnd = GetDlgItem(IDC_STATIC12);
pWnd->GetClientRect(&rect);
CDC* pDC = pWnd->GetDC();
pWnd->Invalidate();
pWnd->UpdateWindow();
CBitmap memBitmap;
CBitmap* pOldBmp = NULL;
memDC.CreateCompatibleDC(pDC);
memBitmap.CreateCompatibleBitmap(pDC,rect.right,rect.bottom);
pOldBmp = memDC.SelectObject(&memBitmap);
memDC.BitBlt(rect.left,rect.top,rect.right,rect.bottom,pDC,0,0,SRCCOPY);
DrawECG(&memDC);
pDC->BitBlt(rect.left,rect.top,rect.right,rect.bottom,&memDC,0,0,SRCCOPY);
memDC.SelectObject(pOldBmp);
memDC.DeleteDC();
memBitmap.DeleteObject();
pWnd->ReleaseDC(pDC);
CDialog::OnTimer(nIDEvent);
}
void CFormComDlg::OnSendData()
{
// TODO: Add your control notification handler code here
CString s;
int i;
if (m_sendControlInfo.GetCurSel()<0)
i=m_sendControlInfo.SetCurSel(1);
else
i = m_sendControlInfo.GetCurSel();
m_sendControlInfo.GetLBText(i,s);
m_ctrComm.SetOutput(COleVariant(s));
}
void CFormComDlg::On_CloseSerial()
{
// TODO: Add your control notification handler code here
if (m_ctrComm.GetPortOpen())
{
m_ctrComm.SetPortOpen(false);
}
else
{
m_ctrComm.SetPortOpen(true);
}
}
上面是MFC中的一部分程序
PC机可以正常的接收来自MSP430F149发送过来的数据,问题是,当我在关闭上位机的串口,然后重新打开串口接收时,就会出现乱码,有时是重新打开又可以正常接收;不过大多数还是显示乱码;
另外 PC机在正常接收时,当我点击COM选择组合框时,组合框的内容不停的闪烁,点击buadrate组合框时,也会不停的闪烁;不知道是什么问题?
本打算在上位机上发送 1 和 2来通知 MSP430F149关闭和打开串口结果是 发送1让MSP430F149停止发送可以实现,
1: PC机发送1给MSP430 通知MSP430关闭串口;
2:PC机发送2 给MSP430 通知MSP430打开串口,进行通信;
当发送2时,让MSP430F149重新打开串口,进行通信时就不能实现,请问各路高手 这到底是什么问题?
PC机程序如下
Code:
void CFormComDlg::OnSendData()
{
// TODO: Add your control notification handler code here
CString s;
int i;
i = m_sendControlInfo.GetCurSel();
m_sendControlInfo.GetLBText(i,s);
m_ctrComm.SetOutput(COleVariant(s));
}
MSP430F149的对应的程序如下
Code:
#pragma vector = UART0RX_VECTOR
__interrupt void receive_ISR(void)
{
_BIC_SR_IRQ(LPM3_bits);
if ( RXBUF0 == 0x31 )
{
UCTL0 |= SWRST;
ME1 &= ~UTXE0; //关闭串口发送功能
UCTL0 &= ~SWRST;
}
if ( RXBUF0 == 0x32 )
{
UCTL0 |= SWRST;
ME1 |= URXE0 + UTXE0 ; // Enable USART0 T/RXD
UCTL0 &= ~SWRST;
}
}
发现采用上面的办法 不能实现串口的关和闭,又采用用MS COMM控件来实现串口的关和闭 ,在正常情况下MSP430发送数据给PC机,PC机可以正常接收,当按下CloseSerial来关闭串口时,然后过会儿重新按下CloseSerial按钮 进行重新接收MSP430发送过来的数据时,就会出现乱码,请问高手用什么办法可以解决这个问题?PC机的程序如下
Code:
void CFormComDlg::On_CloseSerial()
{
// TODO: Add your control notification handler code here
if (m_ctrComm.GetPortOpen())
{
m_ctrComm.SetPortOpen(false);
}
else
{
m_ctrComm.SetPortOpen(true);
}
}
|