搞了几天的PCF8563时钟芯片。。求助。。

2019-07-21 07:07发布

I2C有应答,但是不管写什么数据进去,读出来都是为0。有应答,应该可以说时序没有问题吧?、不知道为什么??晶振起振了。。换了几片的8563都不行。。写数据是按手册来写的。。望搞过的大侠求求助。。
友情提示: 此问题已得到解决,问题已经关闭,关闭后问题禁止继续编辑,回答。
18条回答
qianyuyu
2019-07-23 06:40
--贴一个VHDL程序,基本是可以用的,但是之间感觉比较快。
library ieee;
use ieee.std_logic_1164.all;
use ieee.std_logic_arith.all;
use ieee.std_logic_unsigned.all;
entity rtc is
generic(
constant CLK_RISING_CN : std_logic_vector(5 downto 0):= "010000";
constant CLK_FALING_CN : std_logic_vector(5 downto 0):= "011111";
constant CLK_DEVIDE_MAX: std_logic_vector(5 downto 0):= "011111"
);
port(
nRST    : IN  STD_LOGIC;
SYSCLK  : IN  STD_LOGIC;
rtc_int : IN  STD_LOGIC;
rtc_scl : OUT STD_LOGIC;
rtc_sda : INOUT STD_LOGIC;
poweron : IN STD_LOGIC);
end rtc;
architecture behav of rtc is 
type state2 is (idle,start,tran,recv,wait_2sck,stop);
type state1 is (idle,set_reg,set_time,read_time);
signal pstate2: state2:= idle;
signal pstate1: state1:= idle;
signal data_tran: std_logic_vector(7 downto 0):= (others => '0');
signal data_rec: std_logic_vector(7 downto 0):= (others => '0');
signal tran_en: std_logic:= '0';
signal rec_en: std_logic:= '0';
signal clk_en: std_logic:= '0';
signal stop_en: std_logic:= '0';
signal start_en: std_logic:= '0';
signal cnt_rtc_scl: std_logic_vector(4 downto 0):= (others => '0');   --cnt_rtc_scl * rtc_scl_buf
signal cnt_data: std_logic_vector(7 downto 0):= (others => '0');
signal second: std_logic_vector(5 downto 0):= (others => '0');
signal min: std_logic_vector(5 downto 0):= (others => '0');
signal hour: std_logic_vector(4 downto 0):= (others => '0');
signal days: std_logic_vector(4 downto 0):= (others => '0');
signal weekdays: std_logic_vector(2 downto 0):= (others => '0');
signal months: std_logic_vector(3 downto 0):= (others => '0');
signal years: std_logic_vector(6 downto 0):= (others => '0');
signal centurys: std_logic_vector(6 downto 0):= (others => '0');
signal alarm_min: std_logic_vector(5 downto 0):= (others => '0');
signal alarm_hour: std_logic_vector(4 downto 0):= (others => '0');
signal alarm_days: std_logic_vector(4 downto 0):= (others => '0');
signal alarm_weekdays: std_logic_vector(2 downto 0):= (others => '0');
signal cnt_sck: std_logic_vector(7 downto 0):= (others => '0');    --400KHZ
signal cnt: std_logic_vector(8 downto 0):= (others => '0');        --start mode rtc_sda falling edge is 0.3us 
signal i: std_logic_vector(3 downto 0):= (others => '0');
--variable i:integer range 0 to 127:= 0;
--variable ii:integer range 0 to 127:= 0;
signal ii: std_logic_vector(3 downto 0):= (others => '0');
signal rtc_scl_buf: std_logic:= '0';
signal rtc_sda_in: std_logic:= '0';
signal rtc_sda_out: std_logic:= '0';
signal cnt_start: std_logic_vector(5 downto 0):= (others => '0');
signal cnt_stop: std_logic_vector(5 downto 0):= (others => '0');
signal first: std_logic:= '0';
signal bit_cnt: std_logic_vector(2 downto 0):= "111";
signal cnt_wait: std_logic_vector(7 downto 0):= "00000000";
signal rtc_sda_in_buf1: std_logic:= '0';
signal rtc_sda_in_buf2: std_logic:= '0';
signal cnt_int: std_logic_vector(7 downto 0):= (others => '0');
signal rtc_int_buf: std_logic:= '0';
signal rtc_sda_en: std_logic:= '0';   -- receive word is useful
begin
rtc_scl <= rtc_scl_buf;
rtc_sda <= rtc_sda_out when tran_en = '1' or pstate2 = stop or (pstate2 = wait_2sck and rec_en = '1')else 'Z' ;   --transmit mode or stop mode
rtc_sda_in <= rtc_sda;
rtc_int_buf <= rtc_int;
cnt_int <= cnt_int + '1'when rtc_int_buf = '1' and rtc_int = '0' else cnt_int;   --falling edge
process(SYSCLK,nRST)
begin
if nRST = '0' then
data_tran <= (others => '0');
tran_en <= '0';
rec_en <= '0';
stop_en <= '0';    
start_en <= '0';
elsif rising_edge(SYSCLK) then
case pstate1 is 
when idle =>
if poweron = '0' then
--pstate1 <= set_reg;
pstate1 <= read_time;
first <= '0';
else
pstate1 <= idle;
end if;
when set_reg => 
pstate1 <= set_time;
first <= '0';   --jijun
when set_time =>
if cnt_rtc_scl = 18 and cnt_sck >= 31 then
if first = '0' then     --jijun 
first <= '1';
cnt_data <= (others => '0');
rec_en <= '0';        --receive disable
tran_en <= '1';       --transmit I2C rtc_sda enable
else
cnt_data <= cnt_data + '1';
if cnt_data >= 9 then   
cnt_data <= (others => '0');
pstate1 <= read_time;
stop_en <= '0';
first <= '0';
else 
pstate1 <= set_time;
end if;
end if;
end if;
if cnt_rtc_scl = 18 and cnt_sck >= 31 and first = '1'then
case cnt_data is 
when X"00" => 
data_tran <= X"A2";   --write
tran_en <= '1';
stop_en <= '0';
start_en <= '1';
when X"01" =>
data_tran <= X"02";   --second address
start_en <= '0';
when X"02" =>
data_tran <= X"01";   --second
when X"03" =>
data_tran <= X"01";   --min
when X"04" => 
data_tran <= X"15";   --hour
when X"05" =>
data_tran <= X"11";   --days
when X"06" =>
data_tran <= X"05";   --weekdays
when X"07" => 
data_tran <= X"07";   --months
when X"08" => 
data_tran <= X"0f";   --years
-- when X"09" =>
-- data_tran <= X"1d";   --alarm_min = 59 ; enable minute alarm
  if pstate2 = stop then 
stop_en <= '0';
cnt_data <= cnt_data + '1';
tran_en <= '0';
else 
stop_en <= '1';       --stop mode
end if;
when others => 
stop_en <= '0';
start_en <= '0';
end case;
elsif pstate2 = stop then 
stop_en <= '0';
end if;
when read_time => 
if cnt_rtc_scl = 18 and cnt_sck >= 31 then
if first = '0' then     --base
first <= '1';
cnt_data <= (others => '0');
rec_en <= '1';        --receive disable
tran_en <= '0';       --transmit I2C rtc_sda enable
else
cnt_data <= cnt_data + '1';
if cnt_data >= 13 then   
cnt_data <= (others => '0');
pstate1 <= idle;
stop_en <= '0';
else 
pstate1 <= read_time;
end if;
end if;
end if;

-- if cnt_rtc_scl = 18 and cnt_sck >= 31 then   --18
-- cnt_data <= cnt_data + '1';
-- end if;
-- if cnt_data >= 12 then
-- if cnt_rtc_scl = 18 then     --useful next byte
-- cnt_data <= (others => '0');
-- pstate1 <= idle;
-- stop_en <= '0';
-- end if;
-- else 
-- pstate1 <= read_time;
-- end if;
if cnt_rtc_scl = 18 and cnt_sck >= 31 and first = '1'then
case cnt_data is 
when X"00" => 
data_tran <= X"A2";   --write 
start_en <= '1';
tran_en <= '1'; 
rec_en <= '0';
when X"01" =>
data_tran <= X"02";   --second address
start_en <= '0';
when X"02" =>
data_tran <= X"A3";   --read
start_en <= '1';
tran_en <= '1';
when X"03" =>
start_en <= '0';
tran_en <= '0';
rec_en <= '1';
when X"04" => 
--second <= data_rec(5 downto 0);     --test
when X"05" => 
--second <= data_rec(5 downto 0);     --test
when X"06" =>
--second <= data_rec(5 downto 0);
when X"07" =>
--min <= data_rec(5 downto 0);
when X"08" =>
--hour <= data_rec(4 downto 0);   --02H
when X"09" =>
--days <= data_rec(4 downto 0);
when X"0a" =>
--weekdays <= data_rec(2 downto 0);
when X"0b" => 
--months <= data_rec(3 downto 0);
when X"0c" =>
--years <= data_rec(6 downto 0);
if pstate2 = stop then 
stop_en <= '0';
-- if cnt_rtc_scl = 18 then     --useful next byte
cnt_data <= cnt_data + '1';
-- end if;
else 
   stop_en <= '1';       --stop mode
end if;
rec_en <= '0';
when others => 
stop_en <= '0';
end case;
elsif pstate2 = stop then 
stop_en <= '0';
end if;
if rtc_sda_en = '1' then 
case cnt_data is 
when X"04" => 
--second <= data_rec(5 downto 0);     --test
when X"05" => 
--second <= data_rec(5 downto 0);     --test
when X"06" =>
second <= data_rec(5 downto 0);
when X"07" =>
min <= data_rec(5 downto 0);
when X"08" =>
hour <= data_rec(4 downto 0);   --02H
when X"09" =>
days <= data_rec(4 downto 0);
when X"0a" =>
weekdays <= data_rec(2 downto 0);
when X"0b" => 
months <= data_rec(3 downto 0);
when X"0c" =>
years <= data_rec(6 downto 0);
when others =>
alarm_min <= data_rec(5 downto 0);    --test 
end case;
end if;
when others =>
pstate1 <= idle;
end case;
end if;
end process;
process(SYSCLK,nRST)     --generate rtc_sda
begin
if nRST = '0' then
cnt_start <= (others => '0');
cnt_stop <= (others => '0');
i <= (others => '0');
bit_cnt <= "111";
rtc_sda_en <= '0';
elsif rising_edge(SYSCLK) then 
rtc_sda_in_buf1 <= rtc_sda_in;
rtc_sda_in_buf2 <= rtc_sda_in_buf1;
case pstate2 is 
when idle =>
if start_en = '1' then
if rtc_scl_buf = '0' then    --Time interval can't be too long from start to tran
pstate2 <= start;
else
pstate2 <= idle;
end if;
elsif stop_en = '1' then
pstate2 <= stop;
end if;
when start =>      --falling edge
clk_en <= '0';
if rtc_scl_buf = '1' then 
cnt_start <= cnt_start + '1';
if cnt_start < 16 then
rtc_sda_out <= '1';
elsif cnt_start < 31 then
rtc_sda_out <= '0';
elsif cnt_start = 31 then 
if tran_en = '1' then
pstate2 <= tran;
elsif rec_en = '1' then
pstate2 <= recv;
end if;
cnt_start <= (others => '0');
i <= (others => '0');
end if;
end if;
when tran =>
clk_en <= '1';
if rtc_scl_buf = '0' and cnt_sck = 16 then  --the mid of low level
bit_cnt <= bit_cnt - '1';
rtc_sda_out <= data_tran(conv_integer(bit_cnt));
if bit_cnt = "000" then
pstate2 <= wait_2sck;
end if;
else 
pstate2 <= tran;
end if;
when wait_2sck =>
clk_en <= '1';
if cnt_wait = 62 then
if rec_en = '1' then
rtc_sda_out <= '0';   --acknowledge of master 
rtc_sda_en <= '1';
-- elsif tran_en = '1' then    --why why 
-- rtc_sda_out <= 'Z';
-- else   
-- rtc_sda_out <= '1';
end if;
end if;
if cnt_wait = 124 then
if stop_en = '1' then 
pstate2 <= stop;
elsif start_en = '1' then 
pstate2 <= start;
elsif tran_en = '1' then
pstate2 <= tran;
elsif rec_en = '1' then
pstate2 <= recv;
rtc_sda_en <= '0';
end if;
cnt_wait <= (others => '0');
else 
pstate2 <= wait_2sck;
cnt_wait <= cnt_wait + '1';
end if;
when recv => 
clk_en <= '1';
if rtc_scl_buf = '1' and cnt_sck = 16  then  -- the mid of high level
bit_cnt <= bit_cnt - '1';
data_rec(conv_integer(bit_cnt)) <= rtc_sda_in_buf2;
if bit_cnt = "000" then 
pstate2 <= wait_2sck;
end if;
end if;
when stop =>      --rising edge
if rtc_scl_buf = '1' then
cnt_start <= cnt_start + '1';
if cnt_start < 16 then 
clk_en <= '0';
rtc_sda_out <= '0';
elsif cnt_start < 31 then
rtc_sda_out <= '1';
elsif cnt_start = 31 then 
pstate2 <= idle;
clk_en <= '1';
--pstate2 <= recv;
cnt_start <= (others => '0');
end if;
end if;
when others =>
pstate2 <= idle;
end case;
end if;
end process;

process(SYSCLK,nRST)
begin
if nRST = '0' then   
rtc_scl_buf <= '1';
cnt_sck <= (others => '0');
cnt_rtc_scl <= (others => '0');
elsif rising_edge(SYSCLK) then
--if clk_en = '1' then
if cnt_sck >= 31 then
rtc_scl_buf <= not rtc_scl_buf;
cnt_sck <= (others => '0');
if cnt_rtc_scl >= 18 then 
cnt_rtc_scl <= (others => '0');
else 
cnt_rtc_scl <= cnt_rtc_scl + '1';
end if;
else
rtc_scl_buf <= rtc_scl_buf;
cnt_sck <= cnt_sck + '1';
end if;
--else
-- rtc_scl_buf <= '1';
-- cnt_sck <= (others => '0');
--end if;
end if;
end process;

-- if div_cnt = CLK_DEVIDE_MAX then
-- div_cnt <= (others => '0');
-- bit_cnt <= bit_cnt - '1';
-- if bit_cnt = "000" then
-- pstate <= wait_2sck;
-- end if;                   
-- else
-- div_cnt <= div_cnt + '1';
-- end if;
-- if (div_cnt = CLK_RISING_CN) then
-- rtc_scl_buf <= '1';                    
-- elsif (div_cnt = CLK_FALING_CN) then
-- rtc_scl_buf <= '0';
-- end if;     
end architecture;

一周热门 更多>