本帖最后由 taotie 于 2020-8-22 10:17 編輯
屏幕截圖(38).png (173.69 KB, 下載次數: 67)
下載附件
2020-8-22 09:50 上傳
這是一個外國網站的程序,在bascom avr平臺采用basic語言與匯編語言混合編程。下載回來對其進行部分改造:
去掉lcd16x4液晶改用流行的oled屏仿真。
增加中文設置提示。
注意:源程序是用Bascom-Avr-1.11.9.1編寫的,在新版Bascom-Avr須在非匯編塊中的匯編指令前增加“!”字符
$regfile = "m8def.dat"
$framesize = 32
$swstack = 32
$hwstack = 32
$crystal = 8000000
Config Portb.1 = Output '一個引腳配置為LED輸出
'********* LCD ***************************************************
''設置LCD模塊的針腳,必要時根據您自己的連接
' Config Lcdpin = Pin , Db4 = Portc.2 , Db5 = Portc.3 , Db6 = Portc.4 , Db7 = Portc.5 , E = Portc.1 , Rs = Portc.0
'Config Lcdmode = Port
'Config Lcdbus = 4 '4 bit mode
' Config Lcd = 20 * 4
' Initlcd
'Cursor Off
Config Scl = Portc.5 ' 用I2C引腳Scl = Portc.5 ,Sda = Portc.4
Config Sda = Portc.4
Config Twi = 400000 ' i2c 的速度
I2cinit
$lib "i2c_twi.lbx" ' 不使用模擬I2c的軟件,而是使用twi
$lib "glcdSSD1306-I2C.lib" ' 用glcdSSD1306-I2C庫替換默認庫要添加在bascom avr庫中
#if _build < 20784
Dim ___lcdrow As Byte , ___lcdcol As Byte ' 老版本變量格式進行編譯
#endif
Config Graphlcd = Custom , Cols = 128 , Rows = 64 , Lcdname = "SSD1306" '配置圖形顯示器
'********* ISR Timer 2 ***************************************************
Config Clock = User '配置用于Time$和Date$變量的計時器。
'您可以以128Hz的頻率去抖動(最大延遲4/128 = 0.031s)
Config Timer2 = Timer , Async = On , Prescale = 1 '預分頻器8->16Hz或1->128Hz
On Ovf2 _isr_t2ovf Nosave
Enable Ovf2
Enable Interrupts
Config Date = ymd , Separator = - '配置日期格式 歐洲:dmy 美國:mdy 亞洲:ymd
_sec = 00 : _min = 15 : _hour = 14 : _day = 21 : _month = 08 : _year = 20
Dim Flagrtc_changed As Bit
Dim Tick_128hz As Byte
'********* 輸入鍵和去抖***************************************************
'將按鈕分配給引腳-它們必須全部連接到同一端口!
Const Key_plus = &B0000_1000 '1 =按鈕輸入
Const Key_minus = &B0001_0000
Const Key_enter = &B0010_0000
Const Pinb_mask = Key_plus + Key_minus + Key_enter '過濾輸入的掩碼
Const Pinb_mask_compl = &HFF - Pinb_mask 'Pinb_mask compliment
'這是PortB上的按鈕
Ddrb = Ddrb And Pinb_mask_compl 'DDRB: 0=INPUT 1=OUTPUT
Portb = Portb Or Pinb_mask '1 =激活輸入的內部上拉電阻
Key_port Alias Pinb
Dim Key_state As Byte '0/1按鈕的反轉狀態(tài)(1 =按下)
Dim Key_press As Byte '觸發(fā)按鍵
Dim Key_rep As Byte '自動重復計數器
Dim Key_ct0 As Byte , Key_ct1 As Byte '2 位計數器用于反跳
Const Key_repeat_start = 127 '計時器ISR的編號-1,直到自動重復開始(大約500-1000ms)
Const Key_repeat_next = 15 '定時器ISR的編號-1,用于自動重復重復率(大約125毫秒)
'反跳初始值
Key_ct0 = 255 '攔截程序從按鍵開始
Key_ct1 = 255
'Key_rep = Key_repeat_start 'Paranoia
'********* 一般的 ***************************************************
Dim I As Byte , J As Byte , K As Byte , L As Byte
Dim q As Byte
Dim Setdatetime_index As Byte
Setdatetime_index = 2 '日期數組的第一個索引為1,2 = _min
Dim Date_array(6) As Byte At _sec Overlay '秒/分鐘/小時/天/月/年的數組指定在內存中覆蓋變量。
'********* 主循環(huán) ***************************************************
Do
' Home '光標原點
' Lcd Date$ ; " " ; Time$ '顯示日期和時間
' Locate 2 , 1
' Lcd "Set: " ; Lookupstr(setdatetime_index , Data_dateset) 'var = LOOKUPSTR(索引,標簽)從表中返回一個字符串
Setfont font8x8
Lcdat 2, 16 , Date$
Setfont font12x16
Lcdat 4, 16 ,Time$
Setfont font8x8
'Lcdat 7, 16 , "Set: " ; Lookupstr(setdatetime_index , Data_dateset) 'LOOKUPSTR(索引,標簽)從表中返回一個字符串
'為了節(jié)省電源,在ASM中編寫了128Hz環(huán)路:
Setfont font12x16
q=Lookup(setdatetime_index , Data_set)
Lcdat 7, 16 ,chr(134);chr(135); ": " ; chr(q)
Flagrtc_changed = 0
Enable Interrupts 'Paranoia
'進行節(jié)電循環(huán)直到((Flagrtc_changed = 1)或(Key_press> 0))
Main_1:
Config Powermode = Powersave '配置電源模式=省電模式 如果定時器/計數器2啟用,它將在睡眠期間保持運行
'省電模式僅適用于8535、Mega8、Mega163。
! lds r16,{Key_press} '按下按鈕了嗎?
! TST r16
! BRNE main_2
! lds r16,{flagRTC_Changed} '再來一秒鐘?
! sbrS r16,bit.flagRTC_Changed
! RJMP Main_1
Main_2:
If Key_press > 0 Then Gosub Setdatetime_input
Loop
'---------------------------------------------------------------
'子例程:Setdatetime_input 設置日期時間輸入
'呼叫來源:main
'目的:設定日期和時鐘
'參數:鍵輸入
'---------------------------------------------------------------
Setdatetime_input:
Disable Interrupts '禁用中斷
I = Key_press '讀取鍵
Key_press = 0
L = Lookup(setdatetime_index , Date_max)
If Setdatetime_index = 4 Then
L = Lookup(_month , Date_month)
K = _year And 3
If _month = 2 Then If K = 0 Then Incr L
End If
K = Lookup(setdatetime_index , Date_min)
J = Date_array(setdatetime_index)
If I = Key_plus Then
If J < L Then Incr J Else J = K
End If
If I = Key_minus Then
If J > K Then Decr J Else J = L
End If
Date_array(setdatetime_index) = J
Enable Interrupts '啟用中斷
If I = Key_enter Then
If Setdatetime_index < 6 Then Incr Setdatetime_index Else Setdatetime_index = 1
End If
Return
'********ISR計時器2***************************************************
'---------------------------------------------------------------
'子程序:'u isr_t2ovf
'呼叫來源:定時器2(128Hz)
'目的:RTC,去抖動
'結果:RTC:_秒、_min、\u小時、\u天、\u月、\u年
' '反跳:請參見下文
'---------------------------------------------------------------
$external _soft_clock
Const _sectic = 0 'CONFIG CLOCK = USER,GOSUB <> SECTIC的編譯器語句
_isr_t2ovf:
$asm
push r16
in r16,sreg
push r16 ' 將R16和SREG保存在堆棧中
' 防抖鍵
push r17 '現在保存所有使用的寄存器
push r18
PUSH r19
Call Debounce_port
POP r19 '恢復寄存器
pop r18
pop r17
lds r16,{tick_128hz} '每1/128秒增加一次tick_128
inc r16
sts {tick_128hz},r16
andi r16,128-1 '如果_tick128不是128的倍數
brne _T2OVF_END ' set_digit退出isr,否則已過去一秒鐘
' 該位變量將每隔一秒鐘設置一次
lds r16,{flagRTC_Changed} '位變量
sbr r16,2^bit.flagRTC_Changed
sts {flagRTC_Changed},r16 '注意標志是重置標志的主要代碼責任
' 轉至內部Bascom ISR例行程序:軟時鐘
pop r16 '獲取SREG的內容
!out sreg,r16 '恢復sreg
pop r16
JMP _SOFT_CLOCK '原始RETI
_t2ovf_end:
pop r16 '獲取SREG的內容
!out sreg,r16 '恢復SREG
pop r16
$end Asm
Return '帶著RETI離開isr
'*********防抖******************************************* ************
'------------------------------------------------- --------------
'子程序:Debounce_port
''同時檢測最大 8個按鍵,具有反跳和自動重復功能
'每個鍵被掃描3次以更改狀態(tài)
'使用的寄存器:R16,R17,R18,R19
'變量:鍵0/1的Key_state狀態(tài)
'Key_rep自動重復的重復計數器
'Key_ct0 / Key_ct1 2位計數器,用于反跳
'結果:Key_press:檢測到按下鍵時,引腳位變?yōu)?
'讀出后在Main中重置Key_press的狀態(tài)!
'感謝彼得·丹納格(Peter Dannegger)
'---------------------------------------------------------------
Debounce_port: '大約108個字節(jié)
$asm
in R18, key_port
com R18 '引腳低電平有效
ANDI R18, Pinb_mask '帶Pinb_mask的過濾器引腳
LDS R19, {Key_state}
eor R18, R19 '在引腳輸入處檢測電平變化
LDS R16, {Key_ct0} '8通道2位計數器
LDS R17, {Key_ct1}
and R16, R18 '重置R17中的2位計數器:R16
and R17, R18
com R16 '遞減R17:R16
eor R17, R16
STS {Key_ct0} , R16 '保存計數器
STS {Key_ct1} , R17
and R18, R16 'IF counter=&B11設置數字輸入消隱
and R18, R17
eor R19, R18 '0<->1切換狀態(tài)
STS {Key_state} , R19
LDS R16, {key_press}
and R18, R19
or R16, R18 '檢測到“0->1按鍵
LDS R17, {Key_rep}
tst R19 'Key_state:是否按下任何鍵?
breq Key_isr_rep
dec R17
brpl Key_isr_finish 'IF Key_rep <0 set_digit等待時間到期
mov R16, R19 '自動重復key_press = key_state
ldi R17, key_repeat_next '設置自動回復重復計時器
rjmp Key_isr_finish
Key_isr_rep:
ldi R17, key_repeat_start '重置自動回復開始計時器
Key_isr_finish:
STS {Key_rep} , R17 '保存自動回復計時器
STS {key_press} , R16 '保存去抖鍵
$end Asm
Return
'********* RTC ***************************************************
'如果要使用以下空例程
'時間/日期bascom功能。 您可以根據需要填充它們
Getdatetime:
Return
Settime:
Return
Setdate:
Return
End
'******** 選擇日期和時間 ************************************
Date_min:
Data 0 , 0 , 0 , 0 , 1 , 1 , 0 '‘秒”,“分鐘”,“小時”,“日”,“月”,“年”最小標志
Date_max:
Data 0 , 59 , 59 , 23 , 31 , 12 , 99 '‘秒”,“分鐘”,“小時”,“日”,“月”,“年”最大標志
Date_month:
Data 0 , 31 , 28 , 31 , 30 , 31 , 30 , 31 , 31 , 30 , 31 , 30 , 31 '12個月月末標志
Data_dateset:
Data " " , "Sec " , "Min " , "Hour" , "Day " , "Mon " , "Year" '秒”,“分鐘”,“小時”,“日”,“月”,“年”
Data_set:
Data 0 , 128, 129 , 130 , 131 , 132, 133 '秒”,“分鐘”,“小時”,“日”,“月”,“年”
$include "../font8x8.font"
$include "../font12x16.font"
|