Ⅰ LCD12864的屏總是在閃,我是用51單片機做的,屏帶字型檔,補充里是整個程序,怎麼解決謝謝
看了你的程序,問題在while裡面。沒必要循環初始化你的LCD,將初始化程序放到主函數中。你的顯示函數中也已經包含了清屏指令,不需要在while裡面再次加入清屏指令。如果一定要用,建議你在所有清屏指令後加入的延時夠大。清屏指令過多,延時太少的話,相當於清屏之後又寫入,再清屏再寫入,你看到的就是閃了。
Ⅱ 美的電磁爐三洋單片機晶元TM-S1-01A-A電磁爐各引腳電壓
摘要 你好,很高興為你解答
Ⅲ 單片機CJNE A, 40H, CHK是什麼意思
拍片機上面的這個意思好像是型號不一樣,所以的話它的功能按鍵也是各不相同的。
Ⅳ 用proteus做單片機的模擬實驗,引腳黃色,有經驗的進
……
CD=1;
P0 = 255; //加上這一句試試
status=P0;
return status;
……
Ⅳ 單片機串口通訊關於停止位的問題
發送字元之間增加1bit的時間延時
停止位1個或2個本質上沒有差別,只是時間不同。
停止位長的傳輸准確率高,只是效率低一些。低多少呢?每增加1個停止位低10%。
Ⅵ 單片機c語言宏定義有幾種
宏定義
宏定義是C提供的三種預處理功能的其中一種,這三種預處理包括:宏定義、文件包含、條件編譯
編輯本段1.不帶參數的宏定義:
宏定義又稱為宏代換、宏替換,簡稱「宏」。
格式:
#define 標識符 字元串
其中的標識符就是所謂的符號常量,也稱為「宏名」。
預處理(預編譯)工作也叫做宏展開:將宏名替換為字元串。
掌握"宏"概念的關鍵是「換」。一切以換為前提、做任何事情之前先要換,准確理解之前就要「換」。
即在對相關命令或語句的含義和功能作具體分析之前就要換:
例:
#define PI 3.1415926
把程序中出現的PI全部換成3.1415926
說明:
(1)宏名一般用大寫
(2)使用宏可提高程序的通用性和易讀性,減少不一致性,減少輸入錯誤和便於修改。例如:數組大小常用宏定義
(3)預處理是在編譯之前的處理,而編譯工作的任務之一就是語法檢查,預處理不做語法檢查。
(4)宏定義末尾不加分號;
(5)宏定義寫在函數的花括弧外邊,作用域為其後的程序,通常在文件的最開頭。
(6)可以用#undef命令終止宏定義的作用域
(7)宏定義可以嵌套
(8)字元串" "中永遠不包含宏
(9)宏定義不分配內存,變數定義分配內存。
編輯本段2.帶參數的宏定義:
除了一般的字元串替換,還要做參數代換
格式:
#define 宏名(參數表) 字元串
例如:#define S(a,b) a*b
area=S(3,2);第一步被換為area=a*b; ,第二步被換為area=3*2;
類似於函數調用,有一個啞實結合的過程:
(1)實參如果是表達式容易出問題
#define S(r) r*r
area=S(a+b);第一步換為area=r*r;,第二步被換為area=a+b*a+b;
正確的宏定義是#define S(r) ((r)*(r))
(2)宏名和參數的括弧間不能有空格
(3)宏替換只作替換,不做計算,不做表達式求解
(4)函數調用在編譯後程序運行時進行,並且分配內存。宏替換在編譯前進行,不分配內存
(5)宏的啞實結合不存在類型,也沒有類型轉換。
(6)函數只有一個返回值,利用宏則可以設法得到多個值
(7)宏展開使源程序變長,函數調用不會
(8)宏展開不佔運行時間,只佔編譯時間,函數調用占運行時間(分配內存、保留現場、值傳遞、返回值
C語言宏定義技巧(常用宏定義)
寫好C語言,漂亮的宏定義很重要,使用宏定義可以防止出錯,提高可移植性,可讀性,方便性 等等。
下面列舉一些成熟軟體中常用得宏定義:
1,防止一個頭文件被重復包含
#ifndef COMDEF_H
#define COMDEF_H
//頭文件內容
#endif
2,重新定義一些類型,防止由於各種平台和編譯器的不同,而產生的類型位元組數差異,方便移植。
typedef unsigned char boolean; /* Boolean value type. */
typedef unsigned long int uint32; /* Unsigned 32 bit value */
typedef unsigned short uint16; /* Unsigned 16 bit value */
typedef unsigned char uint8; /* Unsigned 8 bit value */
typedef signed long int int32; /* Signed 32 bit value */
typedef signed short int16; /* Signed 16 bit value */
typedef signed char int8; /* Signed 8 bit value */
3,得到指定地址上的一個位元組或字
#define MEM_B( x ) ( *( (byte *) (x) ) )
#define MEM_W( x ) ( *( (word *) (x) ) )
4,求最大值和最小值
#define MAX( x, y ) ( ((x) > (y)) ? (x) : (y) )
#define MIN( x, y ) ( ((x) < (y)) ? (x) : (y) )
5,得到一個field在結構體(struct)中的偏移量
#define FPOS( type, field ) \
/*lint -e545 */ ( (dword) &(( type *) 0)-> field ) /*lint +e545 */
6,得到一個結構體中field所佔用的位元組數
#define FSIZ( type, field ) sizeof( ((type *) 0)->field )
7,按照LSB格式把兩個位元組轉化為一個Word
#define FLIPW( ray ) ( (((word) (ray)[0]) * 256) + (ray)[1] )
8,按照LSB格式把一個Word轉化為兩個位元組
#define FLOPW( ray, val ) \
(ray)[0] = ((val) / 256); \
(ray)[1] = ((val) & 0xFF)
9,得到一個變數的地址(word寬度)
#define B_PTR( var ) ( (byte *) (void *) &(var) )
#define W_PTR( var ) ( (word *) (void *) &(var) )
10,得到一個字的高位和低位位元組
#define WORD_LO(xxx) ((byte) ((word)(xxx) & 255))
#define WORD_HI(xxx) ((byte) ((word)(xxx) >> 8))
11,返回一個比X大的最接近的8的倍數
#define RND8( x ) ((((x) + 7) / 8 ) * 8 )
12,將一個字母轉換為大寫
#define UPCASE( c ) ( ((c) >= 'a' && (c) <= 'z') ? ((c) - 0x20) : (c) )
13,判斷字元是不是10進值的數字
#define DECCHK( c ) ((c) >= '0' && (c) <= '9')
14,判斷字元是不是16進值的數字
#define HEXCHK( c ) ( ((c) >= '0' && (c) <= '9') ||\
((c) >= 'A' && (c) <= 'F') ||\
((c) >= 'a' && (c) <= 'f') )
15,防止溢出的一個方法
#define INC_SAT( val ) (val = ((val)+1 > (val)) ? (val)+1 : (val))
16,返回數組元素的個數
#define ARR_SIZE( a ) ( sizeof( (a) ) / sizeof( (a[0]) ) )
17,返回一個無符號數n尾的值MOD_BY_Power_OF_TWO(X,n)=X%(2^n)
#define MOD_BY_POWER_OF_TWO( val, mod_by ) \
( (dword)(val) & (dword)((mod_by)-1) )
18,對於IO空間映射在存儲空間的結構,輸入輸出處理
#define inp(port) (*((volatile byte *) (port)))
#define inpw(port) (*((volatile word *) (port)))
#define inpdw(port) (*((volatile dword *)(port)))
#define outp(port, val) (*((volatile byte *) (port)) = ((byte) (val)))
#define outpw(port, val) (*((volatile word *) (port)) = ((word) (val)))
#define outpdw(port, val) (*((volatile dword *) (port)) = ((dword) (val)))
[2005-9-9添加]
19,使用一些宏跟蹤調試
A N S I標准說明了五個預定義的宏名。它們是:
_ L I N E _
_ F I L E _
_ D A T E _
_ T I M E _
_ S T D C _
如果編譯不是標準的,則可能僅支持以上宏名中的幾個,或根本不支持。記住編譯程序
也許還提供其它預定義的宏名。
_ L I N E _及_ F I L E _宏指令在有關# l i n e的部分中已討論,這里討論其餘的宏名。
_ D AT E _宏指令含有形式為月/日/年的串,表示源文件被翻譯到代碼時的日期。
源代碼翻譯到目標代碼的時間作為串包含在_ T I M E _中。串形式為時:分:秒。
如果實現是標準的,則宏_ S T D C _含有十進制常量1。如果它含有任何其它數,則實現是
非標準的。
可以定義宏,例如:
當定義了_DEBUG,輸出數據信息和所在文件所在行
#ifdef _DEBUG
#define DEBUGMSG(msg,date) printf(msg);printf(「%d%d%d」,date,_LINE_,_FILE_)
#else
#define DEBUGMSG(msg,date)
#endif
20,宏定義防止使用是錯誤
用小括弧包含。
例如:#define ADD(a,b) (a+b)
用do{}while(0)語句包含多語句防止錯誤
例如:#difne DO(a,b) a+b;\
a++;
應用時:if(….)
DO(a,b); //產生錯誤
else
解決方法: #difne DO(a,b) do{a+b;\
a++;}while(0)
宏中"#"和"##"的用法
一、一般用法
我們使用#把宏參數變為一個字元串,用##把兩個宏參數貼合在一起.
用法:
#include<cstdio>
#include<climits>
using namespace std;
#define STR(s) #s
#define CONS(a,b) int(a##e##b)
int main()
{
printf(STR(vck)); // 輸出字元串"vck"
printf("%d
", CONS(2,3)); // 2e3 輸出:2000
return 0;
}
Ⅶ 奔騰chk v9.04h 主板1.0A與1.5A有何區別
每個品牌使用的晶元(單片機)廠家是不一樣的,程序也是不一樣的。
2007年以前的電磁爐主要採用20腳單片機+393和339(後兩者是標准邏輯器件),
2008年後的邏輯器件被各單片機集成了,變成了單晶元單片機,腳位數基本也是20腳
2013年以後,電磁爐經過十幾年的發展已經更新好幾代了,電路更成熟,已經變成了16或者18腳的主控單片機。
所以具體你要說是哪個品牌的電磁爐,我可以幫你再查查。你很幸運,我是單片機代理。專業從事小家電和電磁爐的開發和代理。尤其是大功率商用電磁爐,我可是行家。
Ⅷ 單片機中所說的通信協議是什麼
單片機通信協議
現在大部分的儀器設備都要求能過通過上位機軟體來操作,這樣方便調試,利於操作。其中就涉及到通信的過程。在實際製作的幾個設備中,筆者總結出了通信程序的通用寫法,包括上位機端和下位機端等。
1.自定義數據通信協議
這里所說的數據協議是建立在物理層之上的通信數據包格式。所謂通信的物理層就是指我們通常所用到的RS232、RS485、紅外、光纖、無線等等通信方式。在這個層面上,底層軟體提供兩個基本的操作函數:發送一個位元組數據、接收一個位元組數據。所有的數據協議全部建立在這兩個操作方法之上。
通信中的數據往往以數據包的形式進行傳送的,我們把這樣的一個數據包稱作為一幀數據。類似於網路通信中的TCPIP協議一般,比較可靠的通信協議往往包含有以下幾個組成部分:幀頭、地址信息、數據類型、數據長度、數據塊、校驗碼、幀尾。
幀頭和幀尾用於數據包完整性的判別,通常選擇一定長度的固定位元組組成,要求是在整個數據鏈中判別數據包的誤碼率越低越好。減小固定位元組數據的匹配機會,也就是說使幀頭和幀尾的特徵位元組在整個數據鏈中能夠匹配的機會最小。通常有兩種做法,一、減小特徵位元組的匹配幾率。二、增加特徵位元組的長度。通常選取第一種方法的情況是整個數據鏈路中的數據不具有隨即性,數據可預測,可以通過人為選擇幀頭和幀尾的特徵字來避開,從而減小特徵位元組的匹配幾率。使用第二種方法的情況更加通用,適合於數據隨即的場合。通過增加特徵位元組的長度減小匹配幾率,雖然不能夠完全的避免匹配的情況,但可以使匹配幾率大大減小,如果碰到匹配的情況也可以由校驗碼來進行檢測,因此這種情況在絕大多說情況下比較可靠。
地址信息主要用於多機通信中,通過地址信息的不同來識別不同的通信終端。在一對多的通信系統中,可以只包含目的地址信息。同時包含源地址和目的地址則適用於多對多的通信系統。
數據類型、數據長度和數據塊是主要的數據部分。數據類型可以標識後面緊接著的是命令還是數據。數據長度用於指示有效數據的個數。
校驗碼則用來檢驗數據的完整性和正確性。通常對數據類型、數據長度和數據塊三個部分進行相關的運算得到。最簡單的做法可是對數據段作累加和,復雜的也可以對數據進行CRC運算等等,可以根據運算速度、容錯度等要求來選取。
2.上位機和下位機中的數據發送
物理通信層中提供了兩個基本的操作函數,發送一個位元組數據則為數據發送的基礎。數據包的發送即把數據包中的左右位元組按照順序一個一個的發送數據而已。當然發送的方法也有不同。
在單片機系統中,比較常用的方法是直接調用串口發送單個位元組數據的函數。這種方法的缺點是需要處理器在發送過程中全程參與,優點是所要發送的數據能夠立即的出現在通信線路上,能夠立即被接收端接收到。另外一種方法是採用中斷發送的方式,所有需要發送的數據被送入一個緩沖區,利用發送中斷將緩沖區中的數據發送出去。這種方法的優點是佔用處理器資源小,但是可能出現需要發送的數據不能立即被發送的情況,不過這種時延相當的小。對於51系列單片機,比較傾向於採用直接發送的方式,採用中斷發送的方式比較佔用RAM資源,而且對比直接發送來說也沒有太多的優點。以下是51系列單片機中發送單個位元組的函數。
void SendByte(unsigned char ch)
{
SBUF = ch;
while(TI == 0);
TI = 0;
}
上位機中關於串口通信的方式也有多種,這種方式不是指數據有沒有緩沖的問題,而是操作串口的方式不同,因為PC上數據發送基本上都會被緩沖後再發送。對於編程來說操作串口有三種方式,一、使用windows系統中自帶的串口通信控制項,這種方式使用起來比較簡單,需要注意的是接收時的阻塞處理和線程機制。二、使用系統的API直接進行串口數據的讀取,在windows和linux系統中,設備被虛擬為文件,只需要利用系統提供的API函數即可進行串口數據的發送和讀取。三、使用串口類進行串口操作。在此只介紹windows環境下利用串口類編程的方式。
CSerialPort是比較好用的串口類。它提供如下的串口操作方法:
void WriteToPort(char* string, int len);
串口初始化成功後,調用此函數即可向串口發送數據。為了避免串口緩沖所帶來的延時,可以開啟串口的沖刷機制。
3.下位機中的數據接收和協議解析
下位機接收數據也有兩種方式,一、等待接收,處理器一直查詢串口狀態,來判斷是否接收到數據。二、中斷接收。兩種方法的優缺點在此前的一篇關於串口通信的文章中詳細討論過。得出的結論是採用中斷接收的方法比較好。
數據包的解析過程可以設置到不同的位置。如果協議比較簡單,整個系統只是處理一些簡單的命令,那麼可以直接把數據包的解析過程放入到中斷處理函數中,當收到正確的數據包的時候,置位相應的標志,在主程序中再對命令進行處理。如果協議稍微復雜,比較好的方式是將接收的數據存放於緩沖區中,主程序讀取數據後進行解析。也有兩種方式交叉使用的,比如一對多的系統中,首先在接收中斷中解析「連接」命令,連接命令接收到後主程序進入設置狀態,採用查詢的方式來解析其餘的協議。
以下給出具體的實例。在這個系統中,串口的命令非常簡單。所有的協議全部在串口中斷中進行。數據包的格式如下:
0x55, 0xAA, 0x7E, 0x12, 0xF0, 0x02, 0x23, 0x45, SUM, XOR, 0x0D
其中0x55, 0xAA, 0x7E為數據幀的幀頭,0x0D為幀尾,0x12為設備的目的地址,0xF0為源地址,0x02為數據長度,後面接著兩個數據0x23, 0x45,從目的地址開始結算累加、異或校驗和,到數據的最後一位結束。
協議解析的目的,首先判斷數據包的完整性,正確性,然後提取數據類型,數據等數據,存放起來用於主程序處理。代碼如下:
if(state_machine == 0) // 協議解析狀態機
{
if(rcvdat == 0x55) // 接收到幀頭第一個數據
state_machine = 1;
else
state_machine = 0; // 狀態機復位
}
else if(state_machine == 1)
{
if(rcvdat == 0xAA) // 接收到幀頭第二個數據
state_machine = 2;
else
state_machine = 0; // 狀態機復位
}
else if(state_machine == 2)
{
if(rcvdat == 0x7E) // 接收到幀頭第三個數據
state_machine = 3;
else
state_machine = 0; // 狀態機復位
}
else if(state_machine == 3)
{
sumchkm = rcvdat; // 開始計算累加、異或校驗和
xorchkm = rcvdat;
if(rcvdat == m_SrcAdr) // 判斷目的地址是否正確
state_machine = 4;
else
state_machine = 0;
}
else if(state_machine == 4)
{
sumchkm += rcvdat;
xorchkm ^= rcvdat;
if(rcvdat == m_DstAdr) // 判斷源地址是否正確
state_machine = 5;
else
state_machine = 0;
}
else if(state_machine == 5)
{
lencnt = 0; // 接收數據計數器
rcvcount = rcvdat; // 接收數據長度
sumchkm += rcvdat;
xorchkm ^= rcvdat;
state_machine = 6;
}
else if(state _machine == 6 || state _machine == 7)
{
m_ucData[lencnt++] = rcvdat; // 數據保存
sumchkm += rcvdat;
xorchkm ^= rcvdat;
if(lencnt == rcvcount) // 判斷數據是否接收完畢
state_machine = 8;
else
state_machine = 7;
}
else if(state_machine == 8)
{
if(sumchkm == rcvdat) // 判斷累加和是否相等
state_machine = 9;
else
state_machine = 0;
}
else if(state_machine == 9)
{
if(xorchkm == rcvdat) // 判斷異或校驗和是否相等
state_machine = 10;
else
state_machine = 0;
}
else if(state_machine == 10)
{
if(0x0D == rcvdat) // 判斷是否接收到幀尾結束符
{
retval = 0xaa; // 置標志,表示一個數據包接收到
}
state_machine = 0; // 復位狀態機
}
此過程中,使用了一個變數state_machine作為協議狀態機的轉換狀態,用於確定當前位元組處於一幀數據中的那個部位,同時在接收過程中自動對接收數據進行校驗和處理,在數據包接收完的同時也進行了校驗的比較。因此當幀尾結束符接收到的時候,則表示一幀數據已經接收完畢,並且通過了校驗,關鍵數據也保存到了緩沖去中。主程序即可通過retval的標志位來進行協議的解析處理。
接收過程中,只要哪一步收到的數據不是預期值,則直接將狀態機復位,用於下一幀數據的判斷,因此系統出現狀態死鎖的情況非常少,系統比較穩定,如果出現丟失數據包的情況也可由上位機進行命令的補發,不過這種情況筆者還沒有碰到。
對於主程序中進行協議處理的過程與此類似,主程序循環中不斷的讀取串口緩沖區的數據,此數據即參與到主循環中的協議處理過程中,代碼與上面所述完全一樣。
4.上位機中的數據接收和命令處理
上位機中數據接收的過程與下位機可以做到完全一致,不過針對不同的串口操作方法有所不同。對於阻賽式的串口讀函數,例如直接進行API操作或者調用windows的串口通信控制項,最好能夠開啟一個線程專門用於監視串口的數據接收,每接收到一個數據可以向系統發送一個消息。筆者常用的CSerialPort類中就是這樣的處理過程。CSerialPort打開串口後開啟線程監視串口的數據接收,將接收的數據保存到緩沖區,並向父進程發送接收數據的消息,數據將隨消息一起發送到父進程。父進程中開啟此消息的處理函數,從中獲取串口數據後就可以把以上的代碼拷貝過來使用。
CSerialPort向父類發送的消息號如下:
#define WM_COMM_RXCHAR WM_USER+7 // A character was received and placed in the input buffer.
因此需要手動添加此消息的響應函數:
afx_msg LONG OnCommunication(WPARAM ch, LPARAM port);
ON_MESSAGE(WM_COMM_RXCHAR, OnCommunication)
響應函數的具體代碼如下:
LONG CWellInfoView::OnCommunication(WPARAM ch, LPARAM port)
{
int retval = 0;
rcvdat = (BYTE)ch;
if(state_machine == 0) // 協議解析狀態機
{
if(rcvdat == 0x55) // 接收到幀頭第一個數據
state_machine = 1;
else
state_machine = 0; // 狀態機復位
}
else if(state_machine == 1)
{
if(rcvdat == 0xAA) // 接收到幀頭第二個數據
state_machine = 2;
else
state_machine = 0; // 狀態機復位
......
5.總結
以上給出的是通信系統運作的基本雛形,雖然簡單,但是可行。實際的通信系統中協議比這個要復雜,而且涉及到數據包響應、命令錯誤、延時等等一系列的問題,在這樣的一個基礎上可以克服這些困難並且實現出較為穩定可靠的系統
Ⅸ 單片機怎樣用一個鍵控制一個io口的高低電位
這個很簡單,比如:
KEY EQU P1.0
CHK_IO EQU P1.4
KEYCIO:
JB KEY,$ ;鍵按下
JNB KEY,$ ;等鍵抬起
CPL CHK_IO ;IO口取反
RET
Ⅹ 80C51單片機的STB埠和CHK埠是指哪一個啊
STB和CHK是信號狀態,你可以向兩個單片機的介面發送這些信號,然後通過中斷處理程序進行操作的