Ⅰ 51單片機檢測引腳電平變化的c語言程序
#include <reg52.h>
sbit LED0 = P0^0; sbit LED1 = P0^1; sbit LED2 = P0^2; sbit LED3 = P0^3;
sbit LED4 = P0^4; sbit LED5 = P0^5; sbit LED6 = P0^6; sbit LED7 = P0^7;
sbit LED10 = P1^0;
void main() {
LED0 = 0; LED1 = 0; LED2 = 0; LED3 = 0; LED4 = 0; LED5 = 0; LED6 = 0;
LED7 = 0;
LED7 = 1;//假設有變化
if(LED7) {
LED10 = 1;
LED0 = 1; LED1 = 1; LED2 = 1; LED3 = 1; LED4 = 1; LED5 = 1; LED6 = 1; }
}
Ⅱ 51單片機C語言編程
// 51單片機C語言編程,這個時鍾+秒錶可以參考一下。
#include<reg51.h>
#define uchar unsigned char
#define uint unsigned int
sbit qingling=P1^0; //清零
sbit tiaofen=P1^1; //調分
sbit tiaoshi=P1^2; //調時
sbit sounder=P1^7; //naozhong
uint a,b;
uchar hour,minu,sec, //時鍾
hour0,minu0,sec0,//秒錶
hour1,minu1,sec1;
h1,h2,m1,m2,s1,s2,//顯示位
k,s;//狀態轉換標志
uchar code select[]={0x7f,0xbf,0xdf,0xef,0xf7,0xfb,0xfd,0xfe};
uchar code table[]= {0x3f,0x06,0x5b,0x4f,0x66,0x6d,0x7d,0x07,0x7f,0x6f};
/*****************函數聲明***********************/
void keyscan();
void init();
void delay(uchar z);
void display(uchar,uchar,uchar);
void sounde();
/*****************主函數*************************/
void main()
{
init();
while(1)
{
while(TR1)
{
keyscan(); //掃描函數
while(s==1) //s是狀態標志,當s=0時,鬧鍾取消。s=1時,設定鬧鍾時間(也是通過調時,調分函數);
{ //s=2時,鬧鍾工作,時間與設定時刻一致時,鬧鍾響(一分鍾後自動關閉,可手動關閉)。再次切換,s=0.
keyscan(); //s狀態切換(0-》1-》2-》0)通過外部中斷1實現。
display(hour1,minu1,sec1); //鬧鍾時刻顯示
}
display(hour0,minu0,sec0);//時鍾表顯示
while(k) /*k是秒錶狀態(0-》1-》2-》0)通過外部中斷0實現。0秒錶關;1秒錶從零計時;2秒錶停,顯示計時時間*/
{
display(hour,minu,sec); //秒錶顯示
}
}
}
}
/*****************初始化函數***********************/
void init()
{
a=0;
b=0;
k=0;
s=0;
hour0=0;
minu0=0;
sec0=0;
hour=0;
minu=0;
sec=0;
hour1=0;
minu1=0;
sec1=0;
TMOD=0x11; //定時器0,1工作於方式1;賦初值
TH0=(65536-5000)/256;
TL0=(65536-5000)%256;
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
EA=1;
EX0=1; //秒錶中斷
EX1=1; //鬧鍾設定中斷
ET0=1;
ET1=1;
IT0=1; //邊沿觸發方式
IT1=1;
PX0=1;
PX1=1;
TR0=0; //初始,秒錶不工作
TR1=1; //時鍾一開始工作
}
/*****************定時器0中斷*************/
void timer0_int() interrupt 1 //秒錶
{
TH0=(65536-5000)/256;
TL0=(65536-5000)%256;
a++;
if(a==2)
{
a=0;
sec++;
if(sec==100)
{
sec=0; //毫秒級
minu++;
if(minu==60)
{
minu=0; //秒
hour++;
if(hour==60) //分
{
hour=0;
}
}
}
}
}
/*************外部中斷0中斷函數************/
void ex0_int() interrupt 0
{
k++;
if(k==3)
k=0;
if(k==1)
{
TR0=~TR0;
if(TR0==1)
{
hour=0;
minu=0;
sec=0;
}
}
if(k==2)
{
TR0=~TR0;
}
}
/*************外部中斷1中斷函數************/
void ex1_int() interrupt 2
{
s++;
if(s==3)
s=0;
}
/*************定時器1中斷****************/
void timer1_int() interrupt 3 //控制時鍾工作
{
TH1=(65536-50000)/256;
TL1=(65536-50000)%256;
if(s==2)
{
if(hour1==hour0 && minu0==minu1)
sounde();
}
b++;
if(b==20)
{
b=0;
sec0++;
if(sec0==60)
{
sec0=0;
minu0++;
if(minu0==60)
{
minu0=0;
hour0++;
if(hour0==24)
hour0=0;
}
}
}
}
/*************鍵盤掃描****************/
void keyscan()
{
if(s==1)
{
if(qingling==0)
{
delay(10);
if(qingling==0)
{
sec1=0;
minu1=0;
hour1=0;
}
}
if(tiaofen==0)
{
delay(10);
if(tiaofen==0)
{
minu1++;
if(minu1==60)
{
minu1=0;
}
while(!tiaofen);
}
}
if(tiaoshi==0)
{
hour1++;
if(hour1==24)
{
hour1=0;
}
while(!tiaoshi);
}
}
else //調整時鍾時間
{
if(qingling==0)
{
delay(10);
if(qingling==0)
{
sec0=0;
minu0=0;
hour0=0;
}
}
if(tiaofen==0)
{
delay(10);
if(tiaofen==0)
{
minu0++;
if(minu0==60)
{
minu0=0;
}
while(!tiaofen);
}
}
if(tiaoshi==0)
{
hour0++;
if(hour0==24)
{
hour0=0;
}
while(!tiaoshi);
}
}
}
/*************顯示函數****************/
void display(uchar hour,uchar minu,uchar sec)
{
h1=hour/10;
h2=hour%10;
m1=minu/10;
m2=minu%10;
s1=sec/10;
s2=sec%10;
P0=0xff;
P2=table[h1];
P0=select[7];
delay(5);
P0=0xff;
P2=table[h2];
P0=select[6];
delay(5);
P0=0xff;
P2=0x40;;
P0=select[5];
delay(5);
P0=0xff;
P2=table[m1];
P0=select[4];
delay(5);
P0=0xff;
P2=table[m2];
P0=select[3];
delay(5);
P0=0xff;
P2=0x40;
P0=select[2];
delay(5);
P0=0xff;
P2=table[s1];
P0=select[1];
delay(5);
P0=0xff;
P2=table[s2];
P0=select[0];
delay(5);
}
/*************鬧鍾函數****************/
void sounde()
{
sounder=~sounder;
}
/*************延時函數****************/
void delay(uchar z)
{
int x,y;
for(x=z;x>0;x--)
for(y=110;y>0;y--);
}
Ⅲ 求寫一個51單片機C語言程序,不復雜的,在線求助!!!感謝您八輩祖宗!!內有詳細說明
程序簡單,吃完飯飯看有時間沒
#include <reg52.h>
code unsigned char temp[] = {0xC0, 0xF9, 0xA4 , 0xB0, 0x99, 0x92, 0x82, 0xF8, 0x80, 0x90};
unsigned int num;
unsigned char table[4];
void main()
{
TMOD = 0X01;
TH0 = 0XFC;
TL0 = 0X18;
EA = 1;
TR0 = 1;
ET0 = 1;
EX0 = 1;
while(1)
{
;
}
}
void INT0() interrupt 0
{
num += 66;
table[3] = num / 1000;
table[2] = num / 100 % 10;
table[1] = num / 10 % 10;
table[0] = num % 10;
}
void TIMER0() interrupt 1
{
static unsigned char i = 0,j = 0;
TH0 = 0XFC;
TL0 = 0X18;
if(i >= 10)
{
i = 0;
P3 |= 4 << j;
P0 = temp[table[j]];
if(j = 1)
P0 |= 0X7F;
if(j >= 3)
j = 0;
else
j += 1;
}
else
i += 1;
}
差不多就這樣吧,你試試,我沒驗證過,不行再問
Ⅳ 求51單片機C語言編程
#include<reg52.h>
#include<intrins.h>
#define uintunsignedint
sbitk1=P3^2;
sbitbuz=P2^3;
voiddelay(uintt);//延時程序
voidinit();
voidmain()
{
init();
P1=0xfe;
while(1);
}
voiddelay(uintt)//延時程序
{
uinti,j;
for(i=t;i>0;i--)
for(j=112;j>0;j--);
}
voidinit()
{
IT0=0;
EX0=1;
EA=1;
}
voidcroled()interrupt0
{
buz=0;
delay(10);
if(k1==0)
{
while(k1==0);
P1=_crol_(P1,1);
buz=1;
}
}
Ⅳ 求一份51單片機控制mcp42010輸出電壓的C語言程序
親 自己拿錢去買好嗎 世界上就是有太多你這種垃圾 成天伸手拿東西
Ⅵ 求51單片機C語言編程
不能直接定時400ms,可定時50ms,採用中斷方式,中斷8次就是400ms。先計算出定時初始值,X=65536-50000=3CB0H。程序如下
#include<reg51.h>
sbit led=P2^0; //LED燈在P2.0上,0點亮
unsigned char t1n;//對定時50ms中斷計數8次為400ms
void main()
{
TMOD=0x10;
TH1 =0x3C;//晶振頻率=12M,定時50ms
TL1 =0xB0;
EA =1;//開中斷
ET1 =1;
TR1 =1;
led =0;
while(1);
}
void T1_time() interrupt 3
{
TH1 =0x3C;
TL1 =0xB0;
t1n++;
if(t1n>=8)
{
t1n=0;
led=!led;//狀態翻轉
}
}
Ⅶ 怎麼用keil寫51單片機的c語言程序
建立工程,選取所用單片機具體型號,在引導下建立完成工程 選擇c語言編程,建立模板,即可開始,寫C語言代碼。
Ⅷ 求助:單片機C語言程序問題
8051 系列 MCU 的基本結構包括:32 個 I/O 口(4 組8 bit 埠);兩個16 位定時計數器;全雙工串列通信;6 個中斷源(2 個外部中斷、2 個定時/計數器中斷、1 個串口輸入/輸出中斷),兩級中斷優先順序;128 位元組內置RAM;獨立的 64K 位元組可定址數據和代碼區。中斷發生後,MCU 轉到 5 個中斷入口處之一,然後執行相應的中斷服務處理程序。中斷程序的入口地址被編譯器放在中斷向量中,中斷向量位於程序代碼段的最低地址處,注意這里的串口輸入/輸出中斷共用一個中斷向量。8051的中斷向量表如下:
中斷源 中斷向量
---------------------------
上電復位 0000H
外部中斷0 0003H
定時器0 溢出 000BH
外部中斷1 0013H
定時器1 溢出 001BH
串列口中斷 0023H
定時器2 溢出 002BH
interrupt 和 using 都是 C51 的關鍵字。C51 中斷過程通過使用 interrupt 關鍵字和中斷號(0 到 31)來實現。中斷號指明編譯器中斷程序的入口地址中斷序號對應著 8051中斷使能寄存器IE 中的使能位,對應關系如下:
IE寄存器 C51中的 8051的
的使能位 中斷號 中斷源
--------------------------------
IE.0 0 外部中斷0
IE.1 1 定時器0 溢出
IE.2 2 外部中斷1
IE.3 3 定時器1 溢出
IE.4 4 串口中斷
IE.5 5 定時器2 溢出
有 了這一聲明,編譯器不需理會寄存器組參數的使用和對累加器A、狀態寄存器、寄存器B、數據指針和默認的寄存器的保護。只要在中斷程序中用到,編譯器會把它 們壓棧,在中斷程序結束時將他們出棧。C51 支持所有 5 個 8051 標准中斷從 0 到 4 和在 8051 系列(增強型)中多達 27 個中斷源。
using 關鍵字用來指定中斷服務程序使用的寄存器組。用法是:using 後跟一個0 到3 的數,對應著 4 組工作寄存器。一旦指定工作寄存器組,默認的工作寄存器組就不會被壓棧,這將節省 32 個處理周期,因為入棧和出棧都需要 2 個處理周期。這一做法的缺點是所有調用中斷的過程都必須使用指定的同一個寄存器組,否則參數傳遞會發生錯誤。因此對於using,在使用中需靈活取捨。
關於using:
您在文中說明「這一做法的缺點是所有調用中斷的過程都必須使用指定的同一個寄存器組」是不是這個意思?
舉個例子來說:
定義一個函數
void func(unsigned char i) {
...
if(++i==0x12) {
...
}
...
}
有如下一個中斷函數
void int_0(void) interrupt 0 using 1 {
....
}
在默認狀態下,func使用寄存器組0(BANK0),那麼當int_0調用func時是否存在當傳遞參數時會造成參數傳遞錯誤?
謝謝!
如果在中斷服務函數 ISR 中使用寄存器,那麼必須處理好 using 的使用問題:
1、中斷服務函數使用 using 指定與主函數不同的寄存器組(主函數一般使用 Register bank 0)。
2、中斷優先順序相同的ISR 可用 using 指定相同的寄存器組,但優先順序不同的 ISR 必須使用不同的寄存器組,在 ISR 中被調用的函數也要使用 using 指定與中斷函數相同的寄存器組。
3、如果不用 using 指定,在 ISR 的入口,C51 默認選擇寄存器組0,這相當於中斷服務程序的入口首先執行指令:
MOV PSW #0
這點保證了,沒使用 using 指定的高優先順序中斷。可以中斷使用不同的寄存器組的低優先順序中斷。
4、 使用 using 關鍵字給中斷指定寄存器組,這樣直接切換寄存器組而不必進行大量的 PUSH 和 POP 操作,可以節省RAM空間,加速 MCU 執行時間。寄存器組的切換,總的來說比較容易出錯,要對內存的使用情況有比較清晰的認識,其正確性要由你自己來保證。特別在程序中有直接地址訪問的時候, 一定要小心謹慎!至於「什麼時候要用到寄存器組切換」,一種情況是:當你試圖讓兩個(或以上)作業同時運行,而且它們的現場需要一些隔離的時候,就會用上 了。在 ISR 或使用實時操作系統RTOS 中,寄存器非常有用。
寄存器組使用的原則:
1、8051 的最低32 個位元組分成 4 組 8 寄存器。分別為寄存器R0 到R7。寄存器組由PSW 的低兩位選擇。在 ISR 中,MCU 可以切換到一個不同的寄存器組。對寄存器組的訪問不可位定址,C51 編譯器規定使用 using 或 禁止中斷的函數(#pragma disable)均不能返回 bit 類型的值。
2、主程序(main函數)使用一組,如 bank 0;低中斷優先順序的所有中斷均使用第二組,如 bank 1;高中斷優先順序的所有中斷均使用再另外一組,如 bank 2。顯然,同級別的中斷使用同一組寄存器不會有問題,因為不會發生中斷嵌套;而高優先順序的中斷則要使用與低優先順序中斷不同的一組,因為有可能出現在低優先 級中斷中發生高優先順序中斷的情況。編譯器會自動判斷何時可使用絕對寄存器存取。
3、在 ISR 中調用其它函數,必須和中斷使用相同的寄存器組。當沒用 NOAREGS 命令做明確的聲明,編譯器將使用絕對寄存器定址方式訪問函數選定(即用 using 或 REGISTERBANK 指定)的寄存器組,當函數假定的和實際所選的寄存器組不同時,將產生不可預知的結果,從而可能出現參數傳遞錯誤,返回值可能會在錯誤的寄存器組中。
舉一例子:當需要在中斷內和中斷外調用同一個函數,假定按照程序的流程式控制制,不會出現函數的遞歸調用現象,這樣的調用會不會出現問題?若確定不會發生重入情況,則有以下兩種情況:
1、如果 ISR 和主程序使用同一寄存器組(主程序預設使用BANK 0,若 ISR 沒有使用 using 為其指定寄存器區,則預設也使用 BANK 0),則不需其他設置。
2、如果 ISR 和主程序使用不同的寄存器組(主程序預設使用BANK 0,ISR 使用 using 指定了其他 BANK),則被調用函數必須放在:
#pragma NOAREGS
#pragma AREGS
控 制參數對中,指定編譯器不要對該函數使用絕對寄存器定址方式;或者也可在 Options->C51,選中「Don't use absolute register accesses」,使所有代碼均不使用絕對寄存器定址方式(這樣,執行效率將稍有降低)。不論以上的哪一種情況,編譯器均會給出重入警告,需手工更改 OVERLAY 參數,做重入說明。
3、還有一種辦法:如果被調用函數的代碼不是很長,還是將該函數復制一份,用不同的函數名代替,這種情況適合ROM有足夠多餘的空間。
因此,對using關鍵字的使用,如果沒把握,寧可不用,交給編譯系統自己去處理好了。
interrupt xx using y
跟在interrupt 後面的xx 值得是中斷號,就是說這個函數對應第幾個中斷埠,一般在51中
0 外部中斷0
1 定時器0
2 外部中斷1
3 定時器1
4 串列中斷
其它的根舉相應得單片機有自己的含義,實際上c載編譯的時候就是把你這個函數的入口地址方到這個對應中斷的跳轉地址
using y 這個y是說這個中斷函數使用的那個寄存器組就是51裡面一般有4個 r0 -- r7寄存器,如果你的終端函數和別的程序用的不是同一個寄存器組則進入中斷的時候就不會將寄存器組壓入堆棧返回時也不會彈出來節省代碼和時間
一般只有using 0,1,2,3
Ⅸ 51單片機C語言程序
這個很簡單,可以利用單片機的定時器來完成
當有脈沖輸入的時候,啟動定時器,並對定時器的計數值進行清零
每一次脈沖輸入都清零計數值,當脈沖消失後,定時器的計數值達到指定時間則關閉
關閉的同時,調用其它函數,例如你的繼電器控制
需要說明的是,我使用的開發板和你的不見得一樣,所以埠的使用只能你自己修改了
但程序已經經過硬體測試成功,請放心使用,如果滿意記得採納哦
/***************************************************************************/
#include <reg51.h> //51單片機通用頭文件
sbit P24=P1^0; sbit P25=P1^1; sbit P26=P1^2; sbit P27=P1^3;//數碼管位選埠
char table[10]={0xc0,0xf9,0xa4,0xb0,0x99,0x92,0x82,0xf8,0x80,0x90};//數碼管顯示編碼
sbit k=P3^7; sbit KK=P1^4;//定義按鍵和繼電器埠
int t,n,s,fe=0;
/***************************************************************************/
void YS(int hs){int hk;for(;hs>0;hs--){for(hk=100;hk>0;hk--);}}//延時函數
/***************************************************************************/
void XS(int xs)//數碼管顯示
{
char d1,d2,d3,d4;
d1=(xs/1)%10; d2=(xs/10)%10; d3=(xs/100)%10; d4=(xs/1000)%10;
P0=table[d1]; P27=0; YS(5); P27=1;
P0=table[d2]; P26=0; YS(5); P26=1;
P0=table[d3]; P25=0; YS(5); P25=1;
P0=table[d4]; P24=0; YS(5); P24=1;
}
/***************************************************************************/
void main(void)//主函數
{
TMOD=0x01; EA=1; ET0=1; KK=0;//定時器初始化
TH0=(65536-921)/256; TL0=(65536-921)%256;//定時器初值
while(1)
{
XS(t);//調用數碼管顯示函數
if(k==0)//如果按鍵被按下
{
YS(10);//延時去抖動
if(k==0)//如果是有效按鍵
{
TR0=1;//啟動定時器,開始計時
n=0;//每次按鍵都清空定時計數
t++;//按鍵值累加一次
KK=1;//繼電器打開
while(!k){XS(t);}//等待按鍵松開,並調用數碼管顯示,避免黑屏
}
}
if(fe==1)//如果沒按鍵輸入
{
fe=0;t=0;//清空按鍵計數值,並設置標識符
KK=0;//繼電器吸合
}
}
}
/***************************************************************************/
void int1() interrupt 1 //定時器中斷
{
TH0=(65536-1000)/256; TL0=(65536-1000)%256; n++;//n等於100時,則為1秒
if(n>1000){TR0=0;n=0;fe=1;}//如果達到指定時間,則關閉定時器,並設置標識符
}
/***************************************************************************/
Ⅹ 關於51單片機做數碼電壓表時有段程序始終看不懂,請各位單片機高手們指點迷津
void也可以看成是數據類型,只是他是特殊的數據類型,這個類型就是「沒有東西」。
比如一個函數
int a(int b){ }
表示函數的參數是int類型的,返回值是int類型的。如果沒有返回值,也沒有參數,就都把類型名稱寫成void,既然沒有了,那麼也就沒有名稱了,所以b也可以省了,便成了 void a(void) { }。
函數的定義是很基本的c語言知識,這個說起來很啰嗦,隨便看書就能明白了。
void delay(void) 這個函數沒什麼特別意義,只是一個延時而已。因為單片機運行速度很快,數碼管也不是恆定的點亮一個,而是動態掃描的,就是說,先點亮一個位,然後關閉,點亮另一個位。這個過程很快,由於視覺暫留作用,人眼只能看到所有的位都是同時亮的,這個原理和放電影一樣,不過,如果點亮一個後,立即點亮另一個,會因為點亮時間太短,燈還沒全亮就滅了(本人估計的,但應該也是這樣),造成燈光太暗。所以要延時一下。
單片機的電源電壓是5V,那麼所有埠的承受電壓就一定是5V,如果是3.3V單片機,就一定只能承受3.3V,所以測量量程一定是0 至 5V。如果實際測量量程遠遠小於這個范圍,必須用放大器放大。如果量程大於這個范圍,必須分壓。
void convdata(unsigned char i)
這個 i 明顯就是數模轉換得到的結果,作為參數傳遞給這個函數處理。void以及函數參數等名詞術語,說起來就是一本教科書的量,請自行看書,這是很基本的。
dis[0] = i/51 以及後面的兩句,是一個數學問題。(dis[i]就是一個數組,這個不用多言)。
為什麼是51呢?看他的注釋「將0-255級換算成0.00-5.00的電壓數值」。
也就是說,如果測得的電壓是5V,那麼數模轉換的結果就是255,這是一個8位數的最大值,這個數模轉換器的最大值就是8位,所以5V的電壓轉換得到就是255.
然後就可以照推了,如果測得的值是2.5V,那麼得到的值就是255 / 2 = 127.5。也就是說,實際測得的值和這個轉換值的關系是正比的,他們的比值就是 255 / 5 = 51 ,所以用測到的值去除以51,就得到實際值。明白了嗎?如果這樣說還不明白,那就沒辦法了~
然後,為什麼後面又要搞那兩條式子呢?這是因為,要把一個數值在數碼管上顯示出來,必須把一個數值上每一個位的數字單獨處理給數碼管顯示。比如,上面除以51後,得到的數可能會有小數,比如1.45,那麼要把這個數用數碼管顯示出來,就必須把 1、4、5和小數點都單獨取出來。
以這個(i%51)*10/51*2為例:
i%51 , 是 i 除以 51 後的余數。這個數再除以51,再乘以10,再取整,就是第一個小數了。他這個式子把"乘以10"放在前面,是因為如果先除以51,那麼因為i 和 51 都是int類型,結果也必將是int類型,沒有小數,再乘以10也沒意義了。至於後面為什麼還要乘以2,這個還真不清楚,不過他這個dis數組是用來查表的,就是後面的tab[],要看他的表是怎麼定義的。他第一個數沒有乘以2,但是這個數和小數點的顯示有關,可能不顯示小數點的就要乘以2。
後面的求第二個小數,參照這個解釋自己理解一下。