經過一段時間的慎重考慮,在諸多朋友的支持下,決定在接下來的日子里,會盡可能多的寫一些關于應廣多核單片機應用的文章,希望能給有興趣學習了解應廣單片機的朋友提供到點滴幫助。
這個針對應廣雙核、多核單片機應用的系列,會以具體程序為例,在程序中加以注釋,只要條件允許,例程都會經過調試,如果只是編譯沒有調試的,我會注明。
附件中的例程代碼,讀者可以自由使用,不需要通知我,如有可能,希望在代碼中保留我的簽名信息,深表感謝!
例程為利用應廣單片機的特點,用軟件實現理論速率可以達到1M的I2C通訊接口,如果是其它普通單片機,也可以用軟件模擬出高速I2C,不同點是應廣實現模擬后還能夠實現各種控制功能,而其它普通單片則不能。
//-----------------------------------------
//應廣單片機軟件實現高速I2C接口例程(SALVE模式)
//本例僅供參考,歡迎指正程序中的問題
//本例利用應廣單片機的雙核特點
//用一個核專門對I2C接口的IO進行掃描等待
//對I2C接口的高低變化利用應廣特有的IO狀態等待指令高速實現IO口跳變判斷
//利用定時器進行超時判斷
//理論上可以讓模擬的I2C接口達到1M的速率
//2012年12月15日
//
//作者:戴上舉
//郵箱:daishangju@163.com
//博客:forum.eet-cn.com/BLOG_daishangju_334.HTM
//電話:13509678051
//Q Q:1514292225
//-----------------------------------------
.chip p201cs14a
//{{PADAUK_CODE_OPTION
.Code_Option Bootup Slow // 1024 ILRC
.Code_Option LVD 2.79V // Maximum performance = 4 MIPS
.Code_Option Security Enable // Security 3/4 words Enable
//}}PADAUK_CODE_OPTION
//定義I2C接口要用的IO口,用戶可以自己修改這里的IO口定義
I2C_SDA equ pa.0
I2C_SDA_LOW equ set0 I2C_SDA
I2C_SDA_HIGH equ set1 I2C_SDA
I2C_SDA_INPUT equ set0 pac.0
I2C_SDA_OUTPUT equ set1 pac.0
I2C_SCL equ pa.4
//定義I2C設備地址,用戶可以自己修改此地址
I2C_READ_CMD equ 0x7F
I2C_WRITE_CMD equ 0x7E
word init_timer
//byte Xms
//byte ms_cnt
byte i2c_device //用來存放I2C接口地址
byte i2c_write_byte //I2C進行寫操作時存放I2C寫入的數據
byte i2c_read_byte //I2C進行讀操作時候讀出的內容
bit i2c_start_flag
//應廣單片機程序入口,第一條必須為跳轉到第一個內核主程序入口地址的指令,第二條為第二個內核,有幾個內核就有幾條
.romadr 0x000
goto main0
goto main1
//應廣單片機中斷程序入口地址,所有中斷共用同一個入口,需要用戶自己判斷中斷類型
.romadr 0x010
pushaf //壓棧
if(intrq.T16) //判斷是否為定時中斷
{
stt16 init_timer //清內部TIMER計數器
if(i2c_start_flag) //啟動I2C通訊處理后這個標志會被置1
{
I2C_SDA_INPUT
reset //系統復位
}
}
intrq = 0 //清中斷標志
popaf //彈棧
reti //中斷返回
//----------------------------------------
//input: ms
//用該函數可以再4M的頻率下得到近似1毫秒的延時,在第一個內核中調用中斷會導致延時加長
//----------------------------------------
/*delayXms:
while(Xms)
{
wdreset
ms_cnt = 20
while(ms_cnt)
{
delay 195
ms_cnt--
}
Xms--
}
ret*/
//用IO口模擬I2C slave模式的子函數
i2c_slave:
I2C_SDA_INPUT //將SDA設為輸入
i2c_start:
//I2C空閑狀態下SDA和SCL同為高電平,要啟動I2C前初始狀態必須是兩者同為高
stt16 init_timer //清內部TIMER計數器
if(!I2C_SCL) //如果SCL為低,此時不用啟動I2C通訊處理
{
goto i2c_stop
}
if(!I2C_SDA) //如果SDA為低,此時不用啟動I2C通訊處理
{
goto i2c_stop
}
i2c_start_flag = 1 //啟動I2C通訊處理,這個標志位會在定時中斷中用到
//I2C的START信號是SDA和SCL同為高電平裝態下SDA先變為低,然后SCL變為低
//判斷I2C START信號
//等待SDA從高變低
stt16 init_timer //清內部TIMER計數器
wait0 I2C_SDA //應廣特有的等待IO變低指令,等待SDA從高變低,如果長時間沒有變低,會觸發定時中斷,系統復位
nop //加適當延時消除IO抖動的影響
nop
nop
nop
//等待SCL從高變低,原理同上
stt16 init_timer
wait0 I2C_SCL //if overtime MCU will auto reset
nop
nop
nop
nop
//已經判斷為得到有效START信號
//開始接收I2C的器件地址,為了實現高速處理,程序順序處理,沒有使用循環處理方式
i2c_device = 0
stt16 init_timer //device bit7
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.7
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit6
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.6
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit5
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.5
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit4
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.4
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit3
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.3
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit2
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.2
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit1
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.1
}
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //device bit0
wait1 I2C_SCL
nop
nop
nop
nop
if(I2C_SDA)
{
set1 i2c_device.0
}
wait0 I2C_SCL
//nop //后面的比較操作會耗費時間,可以不用延時
//nop
//nop
//nop
if(i2c_device == I2C_READ_CMD) //I2C進行讀操作,同樣為了實現高速處理,程序順序處理,沒有使用循環處理方式
{
//回復slave ACK信號
I2C_SDA_OUTPUT
I2C_SDA_LOW
stt16 init_timer
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit7
if(i2c_read_byte.7)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit6
if(i2c_read_byte.6)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit5
if(i2c_read_byte.5)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit4
if(i2c_read_byte.4)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit3
if(i2c_read_byte.3)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit2
if(i2c_read_byte.2)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit1
if(i2c_read_byte.1)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_read_byte bit0
if(i2c_read_byte.0)
{
I2C_SDA_HIGH
}
else
{
I2C_SDA_LOW
}
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
I2C_SDA_INPUT
stt16 init_timer //master ack/nack
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
nop
nop
nop
nop
stt16 init_timer //END
wait1 I2C_SCL
nop
nop
nop
nop
stt16 init_timer
wait1 I2C_SDA
nop
nop
nop
nop
}
else if(i2c_device == I2C_WRITE_CMD) //I2C是進行寫操作,同樣為了實現高速處理,程序順序處理,沒有使用循環處理方式
{
//slave ACK
I2C_SDA_OUTPUT //--------I2C SDA input/output switch----------
I2C_SDA_LOW
stt16 init_timer
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
I2C_SDA_INPUT
i2c_write_byte = 0
stt16 init_timer //i2c_write_byte bit7
if(I2C_SDA)
{
set1 i2c_write_byte.7
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit6
if(I2C_SDA)
{
set1 i2c_write_byte.6
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit5
if(I2C_SDA)
{
set1 i2c_write_byte.5
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit4
if(I2C_SDA)
{
set1 i2c_write_byte.4
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit3
if(I2C_SDA)
{
set1 i2c_write_byte.3
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit2
if(I2C_SDA)
{
set1 i2c_write_byte.2
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit1
if(I2C_SDA)
{
set1 i2c_write_byte.1
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
stt16 init_timer //i2c_write_byte bit0
if(I2C_SDA)
{
set1 i2c_write_byte.0
}
nop
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
//slave NACK
I2C_SDA_OUTPUT //--------I2C SDA input/output switch----------
I2C_SDA_HIGH
stt16 init_timer
wait1 I2C_SCL
nop
nop
nop
nop
wait0 I2C_SCL
//nop
//nop
//nop
//nop
I2C_SDA_INPUT //--------I2C SDA input/output switch----------
nop
nop
stt16 init_timer //END
wait1 I2C_SCL
nop
nop
nop
nop
stt16 init_timer
wait1 I2C_SDA
//nop
//nop
//nop
//nop
//下面代碼用戶可根據實際情況進行修改,這里是將I2C寫入的數據取反后放到讀操作位置
i2c_read_byte = ~i2c_write_byte
}
i2c_stop:
I2C_SDA_INPUT
i2c_start_flag = 0 //I2C stop work
ret
//----------------FPPA0-------------------
main0:
.ADJUST_OTP_IHRCR 8MIPS // IHRC/2 = 8MIPS, WatchDog Disable, RAM 0,1 temporary be used
sp = 0x30
disgint
inten = 0
mov a,0b000_11_111 //disable timer
mov t16m,a
delay 200
clkmd.0 = 0 //pa.5 as GPIO
//注意IO口的輸入輸出設定
pa = 0b1111_1111
pac = 0b0000_0000
paph = 0b1111_1111
pb = 0b1111_1111
pbc = 0b0000_0000
pbph = 0b1111_1111
init_timer = 7768 //從7768進行校準為100ms
mov a,0b100_11_111
mov t16m,a
stt16 init_timer
delay 200
mov a,0
mov intrq,a
i2c_start_flag = 0 //I2C not start work
// adcdi = 0b0000_0100 //pb2 is analog input
// adcc = 0b10_0010_00 //enable ADC, select pb2
// adcm = 0b000_0100_0 //system clock/16
//adcm = 0b000_0111_0 //system clock/128
set1 fppen.1 //eanble FPPA1
clkmd.1 = 1 //enable watch dog
wdreset //clear watch dog
// Xms = 100
// call delayXms
stt16 init_timer
intrq = 0
inten.T16 = 1 //打開定時中斷
engint
main0_loop:
init_timer = 0
wdreset
//用戶可以在這里添加自己想要的任意代碼,這里可以實現任意一個普通單片機能夠是想的功能
goto main0_loop
//----------------FPPA1-------------------
main1:
sp = 0x38
main1_loop:
call i2c_slave
goto main1_loop
程序中的多個NOP可以用DELAY3代替,用DELAY 指令可以節省程序空間
I2C啟動判斷代碼用下面部分更可靠(2012.12.22)
//wait SDA and SCL high at the same time
while((!I2C_SDA) || (!I2C_SCL))
{
stt16init_timer
nop
nop
nop
nop
}
if(!I2C_SDA)
{
gotoi2c_stop
}
if(!I2C_SCL)
{
gotoi2c_stop
}
代碼已編譯,未調試
-
單片機
+關注
關注
6043文章
44617瀏覽量
638378
發布評論請先 登錄
相關推薦
評論