小学期坑——单片机——铂电阻温度计
我真是给学院的小学期跪了!!! 一周6天扔在实验室!大四了还让不让人好好考研啊!!!这些玩意儿大二大三去搞就行了啊!!!
吐槽完毕.活还是要干的,砖还是要搬的。比起奇葩的电气传动电子的东西真是友好。
队友并没有黄金右手,抽到的题目好魔性。
铂电阻测温度大概是搞个电桥出来当温度传感器通过测电压来搞吧,然而并不会电桥就扔给擅长模电的机智的队友了。
默默揽下码代码的工作。然而我讨厌单片机编程 凸 凸 说得好像会一样==
上位机要求可设置温度上下界,可采集温度并画出波形。
下位机要求能测温,(AD转换),超过上位机设定的上下界时LED屏显示高了还是低了,能与上位机通讯。
==========================
因为懒成一坨了所以完全没更新所以除了安装可以不用管以下的了
拉倒最下面就好了= =
=================================
2015.9.18上位机通讯摸索中
不想编硬件就先从软件下手=w=
VS没有MFC今天才发现= = 重新搞了一遍。大二学的,已经忘光= = 不过并没有什么关系因为重点是搞出和串口的通讯。
step1: MSCOMM安装
因为MSCOMM控件老师直接给了资料所以就用MSCOMM控件了,其实API应该也可以搞,考完研再看吧。
首先VS2015应该是不带MSCOMM的,所以要自己下一个。
http://download.csdn.net/download/flydream0/4583699
把下载的文件解压,搞到一个mscomm32.ocx
一开始企图把他放在windows/sysWOW64下,然后企图注册失败。又复制了一份到windows/system32下。再搞就行了。
把Regsvr32 mscomm32.ocx搞到记事本里,改成.bat,管理员身份运行。 不然各种跪,不信你试试。
(老师的资料是XP的已经过时了,所以照着做各种跪,不知道有没有学弟学妹能搜到我的博客,趴)
step2:先搞个对话框 T T
一路选选选,基于对话框。然后没啥了 = =
在对话框上右键插入ActiveX控件,选Microsoft Communication Control. Version 6.0。就出现了一个长得很丑的= = 电话向的东西。
不要在意这些细节。
Step3.各种乱搞
右击该图标,在快捷菜单中选择“添加变量”,如m_mscomm1。然后在该控件的属性里添加OnComm函数(右侧属性栏上方有一个闪电图标,就是添加消息响应的地方)。
以上是偷懒复制的= =
找出TOOLBOX(VIEW-TOOLBOX),往里面扔两个文本(Static Text)写Upper和Lower免得我忘记= =扔俩编辑框(Edit Control),改一下ID免得忘记 = =
分别给他们添加变量m_send_upper, m_send_lower
留下确定按钮删掉取消(因为懒)
听说老师希望我们把它做得好看一点然而我并没有什么审美,所以还是保持原状吧= =
PS:如果忘了以上的怎么搞,请看这个拯救了我大二小学期的网站(我就不吐槽学校的教材上有多少错了)http://www.jizhuomi.com/software/257.html
Step4:对话框初始化码码码
感觉我马上就要写出一个无脑教程了,不如更无脑一点,丰富一下老师的教程= =
我的解决方案叫poi,所以编辑poiDlg.cpp里的BOOL CpoiDlg::OnInitDialog() 函数
在里面添加代码,具体作用看注释
m_mscomm1.put_CommPort(5); //设置端口COM5 m_mscomm1.put_InBufferSize(1024); //设置输入缓冲区的大小,Bytes m_mscomm1.put_OutBufferSize(512); //设置输出缓冲区的大小,Bytes if (!m_mscomm1.get_PortOpen()) //打开串口 { m_mscomm1.put_PortOpen(true); } m_mscomm1.put_InputMode(1); //设置输入方式为二进制方式 m_mscomm1.put_Settings(L"9600,n,8,1"); //设置波特率等参数 m_mscomm1.put_RThreshold(1); //为1表示有一个字符即引发事件 m_mscomm1.put_InputLen(0);
Step5:加串口接收代码
找到void CpoiDlg::OnCommMscomm1(),在里面添加
待修改版(因为并不知道下位机怎么往上传的,望天)
里面加了一个新的Edit,变量为m_rev,显示接受的值。。。。因为懒所以懒得截图了。
设置了两个全局变量tot,num计算平均值
void CpoiDlg::OnCommMscomm1() { // TODO: 在此处添加消息处理程序代码 VARIANT variant_inp; COleSafeArray safearray_inp; long i = 0; int len; char rxdata[1000]; switch (m_mscomm1.get_CommEvent()) { case 2: //表示接缓冲区内有字符 variant_inp = m_mscomm1.get_Input();//接收数据 safearray_inp = variant_inp; len = safearray_inp.GetOneDimSize(); m_rev = 0; for (i = 0; i < len; i++) { int tmp; safearray_inp.GetElement(&i, &rxdata[i]); tmp = rxdata[i]; m_rev = m_rev * 10 + tmp; } rxdata[i] = '\0'; //m_rev = rxdata; tot += m_rev; num += 1; m_ave = m_rev / num; if (m_rev > m_send_upper) m_stat = "High" else if (m_rev < m_send_lower) m_stat = "Low" else m_stat = "OK"; UpdateData(false); // 将接收数据进行显示 break; default: break; } }
Step6:串口输出(设置)代码
只用往外传两个数。这个到时候写下位机的时候得订个协议?
为何我作死用double存又换int?只因怕老师输入奇怪的东西= =
void CpoiDlg::OnBnClickedOk() { // TODO: 在此添加控件通知处理程序代码 CDialogEx::OnOK(); byte inst[8]; CByteArray sendArr; sendArr.SetSize(8); //发送上界数据 int nowval = (int)m_send_upper; for (int j = 8; j > 0 ; j--) { inst[j] = (nowval & 1); nowval >>= 1; sendArr.SetAt(j, inst[j]); } m_mscomm1.put_Output(COleVariant(sendArr)); //发送下界数据 nowval = (int)m_send_lower; for (int j = 8; j > 0; j--) { inst[j] = (nowval & 1); nowval >>= 1; sendArr.SetAt(j, inst[j]); } m_mscomm1.put_Output(COleVariant(sendArr)); }
Step7:teechart完成绘图
炸裂了为什么这么多要求,摔!
下载teechart,其他操作同S1(记得把名字里的(CN)删一下或者把批处理的文件名改成一样的)
http://download.csdn.net/download/dzh_syh110/4810001
要吐了背背单词睡觉去
================================
UPDATE
下位机部分
#include <reg51.h> #define uchar unsigned char #define uint unsigned int #define Disdata P0 //液晶数据端口 sbit CS = P0^0; sbit SO = P0^1; sbit SI = P0^2; sbit LED_H = P2^0; sbit LED_L = P2^1; uchar upper = 5; uchar lower = 0; uchar cnt = 0; sbit lcden=P1^2; sbit lcdrs=P1^0; sbit rw=P1^1; //液晶 sbit led=P0^3; sbit ALE=P2^3; //锁存控制位 sbit TLC1549_CLK =P2^5; sbit TLC1549_CS =P2^7; sbit TLC1549_DO =P2^6; //DEF TLC uint s; uchar num,num1,num2,num3,num4,num5; uint senddata; void InitUART (void) //串口初始化 { SCON = 0x50; TMOD |= 0x20; //定时器1工作方式2 TH1 = 0xFD; //寄存器装入初值 //TL1 = 0xFD; //寄存器装入初值 TR1 = 1; // 定时器1打开 EA = 1; //总中断打开 ES = 1; //串口中断打开 LED_H = 1; LED_L = 1; } void SendByte(unsigned char dat) //发送一个字节 { SBUF = dat; while(!TI); TI = 0; } void delay30(void) //延时30us { unsigned char a; for(a=13;a>0;a--); } void delay(uint z) //延时zms { uint x,y; for(x=z;x>0;x--) for(y=110;y>0;y--); } void write_com(uchar com) //写液晶屏命令 { lcdrs=0; P0=com; delay(5); lcden=1; delay(5); lcden=0; } void write_data(uchar date) //写液晶屏数据 { lcdrs=1; P0=date; delay(5); lcden=1; delay(5); lcden=0; } void init() //初始化液晶屏 { rw=0; lcden=0; write_com(0x38); write_com(0x0c); write_com(0x06); write_com(0x01); write_com(0x80); delay(1000); } uint ReadTLC1549() //AD 读 { uint temp=0,delay=20; uchar i; TLC1549_CS = 0; for(i=0;i<10;i++) { TLC1549_CLK = 0; temp <<=1; temp |= TLC1549_DO; TLC1549_CLK = 1; //上升沿 } TLC1549_CS = 1; while(delay--); return temp; } void Display(void) //显示数据 { uint calD, calV; uchar v1,v2,v3; float Tar; calD=ReadTLC1549(); calV=(uint)(4.88*calD); //5V 1024个刻度 每个4.88mV Tar= calV*0.001*13.5+13.75; senddata = (uint)(Tar*3); v1 = (uchar)Tar; v2 = v1 % 10; v1 /= 10; v3 = (uchar)(Tar * 10 - v1 * 100 - v2 * 10); write_com(0x80); write_data(0x30+v1); write_com(0x81); write_data(0x30+v2); write_com(0x82); write_data(0x2e); write_com(0x83); write_data(0x30+v3); if(upper<Tar) // to mv { write_com(0x84); write_data('H'); write_com(0x85); write_data('I'); write_com(0x86); write_data('G'); write_com(0x87); write_data('H'); write_com(0x88); write_data(' '); LED_H = 0; LED_L = 1; }else if(lower > Tar){ write_com(0x84); write_data('L'); write_com(0x85); write_data('O'); write_com(0x86); write_data('W'); write_com(0x87); write_data(' '); write_com(0x88); write_data(' '); LED_H = 1; LED_L = 0; } else { write_com(0x84); write_data(' '); write_com(0x85); write_data(' '); write_com(0x86); write_data(' '); write_com(0x87); write_data(' '); write_com(0x88); write_data(' '); LED_L = 1; LED_H = 1; } SendByte(senddata); } void main() { TLC1549_CS=1; TLC1549_CS=0; init(); InitUART(); while(1) { led=0; Display(); delay(1000); } } void UART_SER (void) interrupt 4 //串口中断 { unsigned char Temp; //通讯 起始位为1 设置upper else lower if(RI) //接收中断? { RI=0; Temp=SBUF; //读入缓冲区的值 if(Temp & 128) { upper = Temp ^ 128; } else lower = Temp; } }
上位机部分= =
略微有些复杂。这里只给出dlg.cpp的代码,有心情了再来加注释填坑吧= =
// poiDlg.cpp : 实现文件 // #include "stdafx.h" #include "poi.h" #include "poiDlg.h" #include "afxdialogex.h" #include "CTChart.h" #include "CAxis.h" #include "CAxes.h" #include "CScroll.h" #include "CSeries.h" #include "tchart1.h" #ifdef _DEBUG #define new DEBUG_NEW #endif const int N = 100005; double tot = 0; int num = 0; double rec[N]; // CpoiDlg 对话框 CpoiDlg::CpoiDlg(CWnd* pParent /*=NULL*/) : CDialogEx(IDD_POI_DIALOG, pParent) , m_rev(0) , m_ave(0) , m_stat(_T("")) ,m_send_upper(5) , m_comnum(0) , m_boderate(0) { m_hIcon = AfxGetApp()->LoadIcon(IDR_MAINFRAME); } void CpoiDlg::DoDataExchange(CDataExchange* pDX) { CDialogEx::DoDataExchange(pDX); DDX_Control(pDX, IDC_MSCOMM1, m_mscomm1); DDX_Text(pDX, IDC_EDIT3, m_rev); DDX_Text(pDX, IDC_EDIT_AVER, m_ave); DDX_Text(pDX, IDC_EDIT7, m_stat); DDX_Text(pDX, IDC_EDIT_UPPER, m_send_upper); DDX_Text(pDX, IDC_EDIT_LOWER, m_send_lower); DDX_Control(pDX, IDC_Chart1, m_chart); DDX_CBIndex(pDX, IDC_COMBO1, m_comnum); DDX_CBIndex(pDX, IDC_COMBO2, m_boderate); DDX_Control(pDX, IDC_BUTTON2, m_open); } BEGIN_MESSAGE_MAP(CpoiDlg, CDialogEx) ON_WM_PAINT() ON_WM_QUERYDRAGICON() ON_BN_CLICKED(IDOK, &CpoiDlg::OnBnClickedOk) ON_BN_CLICKED(IDC_BUTTON1, &CpoiDlg::OnBnClickedButton1) ON_BN_CLICKED(IDC_BUTTON2, &CpoiDlg::OnBnClickedButton2) ON_EN_CHANGE(IDC_EDIT_UPPER, &CpoiDlg::OnEnChangeEditUpper) ON_EN_CHANGE(IDC_EDIT_LOWER, &CpoiDlg::OnEnChangeEditLower) ON_CBN_SELCHANGE(IDC_COMBO1, &CpoiDlg::OnCbnSelchangeCombo1) ON_CBN_SELCHANGE(IDC_COMBO2, &CpoiDlg::OnCbnSelchangeCombo2) END_MESSAGE_MAP() // CpoiDlg 消息处理程序 BOOL CpoiDlg::OnInitDialog() { CDialogEx::OnInitDialog(); // 设置此对话框的图标。 当应用程序主窗口不是对话框时,框架将自动 // 执行此操作 SetIcon(m_hIcon, TRUE); // 设置大图标 SetIcon(m_hIcon, FALSE); // 设置小图标 // TODO: 在此添加额外的初始化代码 m_mscomm1.put_CommPort(6); //端口号为6 m_mscomm1.put_InBufferSize(1024); //设置输入缓冲区的大小,Bytes m_mscomm1.put_OutBufferSize(512); //设置输出缓冲区的大小,Bytes if (!m_mscomm1.get_PortOpen()) //打开串口 { m_mscomm1.put_PortOpen(true); } m_mscomm1.put_InputMode(1); //设置输入方式为二进制方式 m_mscomm1.put_Settings(L"9600,n,8,1"); //设置波特率等参数 m_mscomm1.put_RThreshold(1); //为1表示有一个字符即引发事件 m_mscomm1.put_InputLen(0); return TRUE; // 除非将焦点设置到控件,否则返回 TRUE } // 如果向对话框添加最小化按钮,则需要下面的代码 // 来绘制该图标。 对于使用文档/视图模型的 MFC 应用程序, // 这将由框架自动完成。 void CpoiDlg::OnPaint() { if (IsIconic()) { CPaintDC dc(this); // 用于绘制的设备上下文 SendMessage(WM_ICONERASEBKGND, reinterpret_cast<WPARAM>(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(); } } //当用户拖动最小化窗口时系统调用此函数取得光标 //显示。 HCURSOR CpoiDlg::OnQueryDragIcon() { return static_cast<HCURSOR>(m_hIcon); } BEGIN_EVENTSINK_MAP(CpoiDlg, CDialogEx) ON_EVENT(CpoiDlg, IDC_MSCOMM1, 1, CpoiDlg::OnCommMscomm1, VTS_NONE) END_EVENTSINK_MAP() void CpoiDlg::OnCommMscomm1() { // TODO: 在此处添加消息处理程序代码 VARIANT variant_inp; COleSafeArray safearray_inp; long i = 0; int len; char rxdata[1000]; switch (m_mscomm1.get_CommEvent()) { case 2: //表示接缓冲区内有字符 variant_inp = m_mscomm1.get_Input();//接收数据 safearray_inp = variant_inp; len = safearray_inp.GetOneDimSize(); m_rev = 0; for (i = 0; i < len; i++) { int tmp; safearray_inp.GetElement(&i, &rxdata[i]); tmp = rxdata[i]; m_rev = m_rev * 16 + tmp; } rxdata[i] = '\0'; m_rev =( (int)(m_rev / 3.0 * 10)) / 10.0; //m_rev = rxdata; tot += m_rev; num += 1; rec[(int)num%N] = m_rev; m_ave = tot / num; if (m_rev > m_send_upper) m_stat = "High"; else if (m_rev < m_send_lower) m_stat = "Low"; else m_stat = "OK"; for (int i = 1; i <= num; i++) { CSeries serDemo1 = (CSeries)m_chart.Series(0); serDemo1.AddNullXY(i, rec[i], NULL); } UpdateData(false); // 将接收数据进行显示 break; default: break; } } void CpoiDlg::OnBnClickedOk() { // TODO: 在此添加控件通知处理程序代码 CDialogEx::OnOK(); } void CpoiDlg::OnEnChangeEdit8() { // TODO: 如果该控件是 RICHEDIT 控件,它将不 // 发送此通知,除非重写 CDialogEx::OnInitDialog() // 函数并调用 CRichEditCtrl().SetEventMask(), // 同时将 ENM_CHANGE 标志“或”运算到掩码中。 // TODO: 在此添加控件通知处理程序代码 } void CpoiDlg::OnBnClickedButton1() { // TODO: 在此添加控件通知处理程序代码 CByteArray sendArr; sendArr.SetSize(1); //发送上界数据 m_mscomm1.put_OutBufferCount(0); int nowval = (int)m_send_upper; nowval |= 128; sendArr.SetAt(0, nowval); m_mscomm1.put_Output(COleVariant(sendArr)); //发送下界数据 m_mscomm1.put_OutBufferCount(0); nowval = (int)m_send_lower; sendArr.SetAt(0, nowval); m_mscomm1.put_Output(COleVariant(sendArr)); } void CpoiDlg::OnBnClickedButton2() { // TODO: 在此添加控件通知处理程序代码 UpdateData(true); m_mscomm1.put_CommPort(m_comnum + 1); //设置端口 m_mscomm1.put_InBufferSize(1024); //设置输入缓冲区的大小,Bytes m_mscomm1.put_OutBufferSize(512); //设置输出缓冲区的大小,Bytes if (!m_mscomm1.get_PortOpen()) //打开串口 { m_mscomm1.put_PortOpen(true); } m_mscomm1.put_InputMode(1); //设置输入方式为二进制方式 int boderate = (2 << m_boderate) * 4800; CString str; str.Format(_T("%d"), boderate); str += ",n,8,1"; m_mscomm1.put_Settings(str); //设置波特率等参数 m_mscomm1.put_RThreshold(1); //为1表示有一个字符即引发事件 m_mscomm1.put_InputLen(0); } void CpoiDlg::OnEnChangeEditUpper() { // TODO: 如果该控件是 RICHEDIT 控件,它将不 // 发送此通知,除非重写 CDialogEx::OnInitDialog() // 函数并调用 CRichEditCtrl().SetEventMask(), // 同时将 ENM_CHANGE 标志“或”运算到掩码中。 // TODO: 在此添加控件通知处理程序代码 UpdateData(true); } void CpoiDlg::OnEnChangeEditLower() { // TODO: 如果该控件是 RICHEDIT 控件,它将不 // 发送此通知,除非重写 CDialogEx::OnInitDialog() // 函数并调用 CRichEditCtrl().SetEventMask(), // 同时将 ENM_CHANGE 标志“或”运算到掩码中。 // TODO: 在此添加控件通知处理程序代码 UpdateData(true); } void CpoiDlg::OnCbnSelchangeCombo1() { // TODO: 在此添加控件通知处理程序代码 UpdateData(true); } void CpoiDlg::OnCbnSelchangeCombo2() { // TODO: 在此添加控件通知处理程序代码 UpdateData(true); }