Ⅰ 51單片機程序編寫
/*這是用LCD顯示所測溫度的代碼,你參考一下,如果沒問題的話,其他的功能你再添加就好了,不難*/
#include<reg52.h>
#include<intrins.h>
#define uint unsigned int
#define uchar unsigned char
#define Nack_number 10
//**************埠定義**************************************************
uchar flag; //LCD控制線介面
sbit RS=P1^0; //RS端
sbit RW=P1^1; //讀寫端
sbit LCDE=P2^5; //使能端
//mlx90614埠定義
sbit SCK=P2^1; //時鍾線
sbit SDA=P2^2; //數據線
//************數據定義****************************************************
bdata uchar flag1; //可位定址數據
sbit bit_out=flag1^7;
sbit bit_in=flag1^0;
uchar tempH,tempL,err;
//************************** LCD1602 ***********************************
//向LCD寫入命令或數據*****************************************************
#define LCD_COMMAND 0 //命令
#define LCD_DATA 1 // 數據
#define LCD_CLEAR_SCREEN 0x01 // 清屏
#define LCD_HOMING 0x02 // 游標返回原點
//設置顯示模式******* 0x08+ *********************************************
#define LCD_SHOW 0x04 //顯示開
#define LCD_HIDE 0x00 //顯示關
#define LCD_CURSOR 0x02 //顯示游標
#define LCD_NO_CURSOR 0x00 //無游標
#define LCD_FLASH 0x01 //游標閃動
#define LCD_NO_FLASH 0x00 //游標不閃動
//設置輸入模式********** 0x04+ ********************************************
#define LCD_AC_UP 0x02 //游標右移 AC+
#define LCD_AC_DOWN 0x00 //默認 游標左移 AC-
#define LCD_MOVE 0x01 //畫面可平移
#define LCD_NO_MOVE 0x00 //默認 畫面不移動
//************************** mlx90614 ***********************************
//command mode 命令模式
#define RamAccess 0x00 //對RAM操作
#define EepomAccess 0x20 //對EEPRAM操作
#define Mode 0x60 //進入命令模式
#define ExitMode 0x61 //退出命令模式
#define ReadFlag 0xf0 //讀標志
#define EnterSleep 0xff //進入睡眠模式
//ram address read only RAM地址(只讀)
#define AbmientTempAddr 0x03 //周圍溫度
#define IR1Addr 0x04
#define IR2Addr 0x05
#define LineAbmientTempAddr 0x06 //環境溫度
/*0x0000 0x4074 16500 0.01/單元
-40 125*/
#define LineObj1TempAddr 0x07 //目標溫度,紅外溫度
/*0x27ad-0x7fff 0x3559 22610 0.02/單元
-70.01-382.19 0.01 452.2*/
#define LineObj2TempAddr 0x08
//eepom address EEPROM地址
#define TObjMaxAddr 0x00 //測量范圍上限設定
#define TObjMinAddr 0x01 //測量范圍下限設定
#define PWMCtrlAddr 0x02 //PWM設定
#define TaRangeAddr 0x03 //環境溫度設定
#define KeAddr 0x04 //頻率修正系數
#define ConfigAddr 0x05 //配置寄存器
#define SMbusAddr 0x0e //器件地址設定
#define Reserverd1Addr 0x0f //保留
#define Reserverd2Addr 0x19 //保留
#define ID1Addr 0x1c //ID地址1
#define ID2Addr 0x1d //ID地址2
#define ID3Addr 0x1e //ID地址3
#define ID4Addr 0x1f //ID地址4
//************函數聲明*****************************************************
void start(); //MLX90614發起始位子程序
void stop(); //MLX90614發結束位子程序
uchar ReadByte(void); //MLX90614接收位元組子程序
void send_bit(void); //MLX90614發送位子程序
void SendByte(uchar number); //MLX90614接收位元組子程序
void read_bit(void); //MLX90614接收位子程序
void delay(uint N); //延時程序
uint readtemp(void); //讀溫度數據
void init1602(void); //LCD初始化子程序
void busy(void); //LCD判斷忙子程序
void cmd_wrt(uchar cmd); //LCD寫命令子程序
void dat_wrt(uchar dat); //LCD寫數據子程序
void display(uint Tem); //顯示子程序
void Print(uchar *str); //字元串顯示程序
//*************主函數*******************************************
void main()
{
uint Tem; //溫度變數
SCK=1;
SDA=1;
delay(4);
SCK=0;
delay(1000);
SCK=1;
init1602(); //初始化LCD
while(1)
{
Tem=readtemp(); //讀取溫度
cmd_wrt(0x01); //清屏
Print(" Temperature: "); //顯示字元串 Temperature: 且換行
display(Tem); //顯示溫度
Print(" ^C"); //顯示攝氏度
delay(10000); //延時再讀取溫度顯示
}
}
void Print(uchar *str) //字元串顯示程序
{
while(*str!='') //直到字元串結束
{
dat_wrt(*str); //轉成ASCII碼
str++; //指向下一個字元
}
}
//*********輸入轉換並顯示*********
void display(uint Tem)
{
uint T,a,b;
T=Tem*2;
if(T>=27315) //溫度為正
{
T=T-27315; //
a=T/100; //溫度整數
b=T-a*100; //溫度小數
if(a>=100) //溫度超過100度
{
dat_wrt(0x30+a/100); //顯示溫度百位
dat_wrt(0x30+a%100/10); //顯示溫度十位
dat_wrt(0x30+a%10); //顯示溫度個位
}
else if(a>=10) //溫度超過10度
{
dat_wrt(0x30+a%100/10); //顯示溫度十位
dat_wrt(0x30+a%10); //顯示溫度個位
}
else //溫度不超過10度
{
dat_wrt(0x30+a); //顯示溫度個位
}
dat_wrt(0x2e); //顯示小數點
if(b>=10) //溫度小數點後第1位數不等於0
{
dat_wrt(0x30+b/10); //顯示溫度小數點後第1位數
dat_wrt(0x30+b%10); //顯示溫度小數點後第2位數
}
else //溫度小數點後第1位數等於0
{
dat_wrt(0x30); //顯示溫度小數點後第1位數0
dat_wrt(0x30+b); //顯示溫度小數點後第2位數
}
}
else //溫度為負
{
T=27315-T;
a=T/100;
b=T-a*100;
dat_wrt(0x2d); //顯示負號
if(a>=10) //溫度低於負10度
{
dat_wrt(0x30+a/10); //顯示溫度十位
dat_wrt(0x30+a%10); //顯示溫度個位
}
else //溫度高於負10度
{
dat_wrt(0x30+a); //顯示溫度個位
}
dat_wrt(0x2e); //顯示小數點
if(b>=10) //溫度小數點後第1位數不等於0
{
dat_wrt(0x30+b/10); //顯示溫度小數點後第1位數
dat_wrt(0x30+b%10); //顯示溫度小數點後第2位數
}
else //溫度小數點後第1位數等於0
{
dat_wrt(0x30); //顯示溫度小數點後第1位數0
dat_wrt(0x30+b); //顯示溫度小數點後第2位數
}
}
}
//************************************
void start(void) //停止條件是 SCK=1時,SDA由1到0
{
SDA=1;
delay(4);
SCK=1;
delay(4);
SDA=0;
delay(4);
SCK=0;
delay(4);
}
//------------------------------
void stop(void) //停止條件是 SCK=1時,SDA由0到1
{
SCK=0;
delay(4);
SDA=0;
delay(4);
SCK=1;
delay(4);
SDA=1;
}
//---------發送一個位元組---------
void SendByte(uchar number)
{
uchar i,n,dat;
n=Nack_number; //可以重發次數
Send_again:
dat=number;
for(i=0;i<8;i++) //8位依次發送
{
if(dat&0x80) //取最高位
{
bit_out=1; //發1
}
else
{
bit_out=0; //發0
}
send_bit(); //發送一個位
dat=dat<<1; //左移一位
}
read_bit(); //接收1位 應答信號
if(bit_in==1) //無應答時重發
{
stop();
if(n!=0)
{
n--; //可以重發Nack_number=10次
goto Repeat; //重發
}
else
{
goto exit; //退出
}
}
else
{
goto exit;
}
Repeat:
start(); //重新開始
goto Send_again; //重發
exit: ; //退出
}
//-----------發送一個位---------
void send_bit(void)
{
if(bit_out==1)
{
SDA=1; //發1
}
else
{
SDA=0; //發0
}
_nop_();
SCK=1; //上升沿
delay(4);delay(4);
SCK=0;
delay(4);delay(4);
}
//----------接收一個位元組--------
uchar ReadByte(void)
{
uchar i,dat;
dat=0; //初值為0
for(i=0;i<8;i++)
{
dat=dat<<1; //左移
read_bit(); //接收一位
if(bit_in==1)
{
dat=dat+1; //為1時對應位加1
}
}
SDA=0; //發送應答信號0
send_bit();
return dat; //帶回接收數據
}
//----------接收一個位----------
void read_bit(void)
{
SDA=1; //數據端先置1
bit_in=1;
SCK=1; //上升沿
delay(4);delay(4);
bit_in=SDA; //讀數據
_nop_();
SCK=0;
delay(4);delay(4);
}
//------------------------------
uint readtemp(void)
{
SCK=0;
start(); //開始條件
SendByte(0x00); //發送從地址00
SendByte(0x07); //發送命令
start(); //開始條件
SendByte(0x01); //讀從地址00
bit_out=0;
tempL=ReadByte(); //讀數據低位元組
bit_out=0;
tempH=ReadByte(); //讀數據高位元組
bit_out=1;
err=ReadByte(); //讀錯誤信息碼
stop(); //停止條件
return(tempH*256+tempL);
}
//******************LCD顯示子函數***********************
void init1602(void) //初始化LCD
{
cmd_wrt(0x01); //清屏
cmd_wrt(0x0c); //開顯示,不顯示游標,不閃爍
cmd_wrt(0x06); //完成一個字元碼傳送後,游標左移,顯示不發生移位
cmd_wrt(0x38); //16×2顯示,5×7點陣,8位數據介面
}
void busy(void) //LCD忙標志判斷
{
flag=0x80; //賦初值 高位為1 禁止
while(flag&0x80) //讀寫操作使能位禁止時等待 繼續檢測
{
P0=0xff;
RS=0; //指向地址計數器
RW=1; //讀
LCDE=1; //信號下降沿有效
flag=P0; //讀狀態位 高位為狀態
LCDE=0;
}
}
void cmd_wrt(uchar cmd) //寫命令子函數
{
LCDE=0;
busy(); //檢測 讀寫操作使能嗎
P0=cmd; //命令
RS=0; //指向命令計數器
RW=0; //寫
LCDE=1; //高電平有效
LCDE=0;
}
void dat_wrt(uchar dat) //寫數據子函數
{
busy(); //檢測 讀寫操作使能嗎
LCDE=0;
if(flag==16)
{
RS=0; //指向指令寄存器
RW=0; //寫
P0=0XC0; //指向第二行
LCDE=1; //高電平有效
LCDE=0;
}
RS=1; //指向數據寄存器
RW=0; //寫
P0=dat; //寫數據
LCDE=1; //高電平有效
LCDE=0;
}
//------------延時--------------
void delay(uint n)
{
uint j;
for(j=0;j<n;j++)
{
_nop_();
}
}
Ⅱ 51單片機的編程問題
1:C51編譯器如何區分位地址和位元組地址
是靠預定義實現的,比如:sfr P0 = 0x80; sbit P0_0 = 0x80;前者聲明了P0埠地址位於0x80,後者說明了P0埠的bit0,即P0.0位於位地址空間0x80處。這2個0x80具有完全不同的含義,靠關鍵字sfr和sbit來區別。這樣當程序被編譯時,編譯器會依此編譯成相應的匯編語言。例如:
C51語句: P0 = 1;
P0聲明為sfr,因此編譯成:mov 80h,01h,將把0x01數據送入0x80單元,由於0x80單元物理上對應P0埠,因此,P0.0腳將輸出高電平(其實是呈現高阻態,P0口獨有的),其他.1-.7腳輸出低電平。
C51語句: P0_0 = 1;
P0_0聲明為sbit,因此編譯成:setb 80h,這將把位地址空間的0x80地址的bit的值置1。這個位正是P0口的bit0,執行後,P0.0將輸出高阻態。而P0.1-.7不會變化。
2:C51為什麼要嵌套匯編
51單片機一個顯著優點就是指令執行時間固定,因此可以適應時序要求嚴格的場合。例如符合ISO7816協議的cpu卡的讀寫,對時序要求比較嚴格。其實就是用io腳做出來的同步半雙工串口。支持cpu卡的程序一般比較龐大,需要用c51來組織,但是由於c編譯的不確定性,必須把底層程序封裝成匯編語言模塊嵌入到工程中。這就帶來幾個問題:如何聲明函數、參數如何傳遞等。限於篇幅,不能說得很細。下面舉例:
匯編程序單獨保存一個文件,加入到工程中,函數如下:
_proc_a:
mov a, r7
inc a
mov r7, a
ret
用c語言在.h文件中聲明: extern unsigned char proc_a(unsigned char val);
調用時形如: retvalue = proc_a(0x11);
說明:
a:匯編程序如果帶參數,則需要在匯編程序前多加一個下劃線。而聲明它的地方不用加(偉福編譯器這么要求的)。
b:函數的形參中第一參數用R7傳遞,函數返回值用R7返回,這是C51的通用規范。其他參數都有相應規定。函數可以返回一個位,用psw的c位返回。c:上面的語句,執行順序是把0x11給R7,然後跳轉子程序,子程序將它加1後送回。
d:函數跳轉到匯編程序時,本區的R0-R7,A,B,PSW,DPTR等寄存器可以供子程序使用,不必考慮調用後是否要恢復這些常規資源。上例中,A的值被函數使用了,編程者不必恢復調用前的值。
Ⅲ STC89C51單片機控制SIM800C給手機發簡訊
可能是你的程序寫的有問題,這個模塊是支持串口AT指令的,你先用串口下載線直接連SIM800C模塊然後打開STC的下載軟體STC~ISP裡面的串口調試助手,選好埠、波特率、校驗位、停止位,從電腦上直接發送操作命令,如果可以運行,就是你單片機程序寫的有問題