STM8自学笔记(推荐STM8很好的入门电子书)
无刷直流电机控制应用+基于STM8S系列单片机---电子书
【精华资料】STM8Sxx固件库FOR IAR
基于STM8的DALI (数字可寻址调光协议)
分享STM8 风驰光盘的资料,是完整的(包括原理图+例程+PDF注释)
《无刷直流电机控制应用 基于STM8S系列单片机》
STM8S库函数中文参考 小软件
【资料分享】STM8L的智能手持血糖监测设备的源码
基于STM8S207工程模板
【培训资料】STM8系列PPT培训资料
微信公众号
手机版
/*==========================================================================================================
函数功能: 本函数是I2C总线通信接收和发送作业不间断循环调用运行函数。& e1 F; _4 ]% O4 D9 q2 e
备注: ▲.注意:本函数为消息任务队列函数,要在主函数中不间断循环调用运行。
▲.当I2C总线工作于从机方式时,I2C总线中断总是处于使能状态,以便
I2C总线处于随时接收数据状态。. A4 m3 x, T, K9 x
==========================================================================================================*/
void CommI2cCircleFunc (void)
{
#ifdef DEBUG
unsigned char i; // 循环计数器变量
unsigned char j;9 D; t2 ~+ E9 D1 H, f& P4 q
unsigned char hex_data[2];* g' V' E" B0 R$ H9 p
unsigned char *ptr;; b( Z1 M0 o8 _3 R4 K
#endif
unsigned char i; // 循环计数器变量
CommI2cDataStru *pI2c; // 指向I2C总线通讯收发数据处理变量的指针
! d7 Z$ @$ k0 G; e
pI2c = &gstvI2c; // 取I2C总线通讯收发数据处理变量的首个地址
#ifdef PreCommI2cUseSingleMasterMode // “I2C总线工作于单主机方式”的条件编译
if ( (gbitI2c.Error == SET) // 如果I2C总线通讯收发作业发生错误,* r* c7 u: R1 v5 r9 j8 O, f7 d
&& ( ! CommI2cBusBusy( )) ) // 且I2C总线收发器处于空闲状态?8 l1 i4 T! }) ]2 S, ?) J
{8 F% u/ Q' g% f5 l
if (pI2c->Cycle > cI2cErrorMax) // 检查重新启动收发作业错误次数是否大于最大值?2 c' y' R% ?) J
{
pI2c->Cycle = 0x00; // I2C总线的重新启动收发作业发生错误次数清0. ~) |8 \, {. c. s
gbitI2c.Error = CLEAR; // 清除“通讯收发作业发生错误”标志
gbitI2c.Busy = CLEAR; // 清除“I2C总线〖忙〗”标志( X# N6 Z: `& }& U3 L
#ifdef _SYSTEM_ERROR_MANAGE_H_
sys_error_type |= SYS_ERROR_TYPE_IS_GENERAL; // 置【普通】错误类型消息任务标志位/ d j$ p& Z. u6 F
sys_error_value = SYS_ERROR_COMM_I2CBUS ; // 置“I2C总线通信收发作业”错误代码值
#endif1 F0 e/ N/ t2 M8 s v2 f
}3 W' `( O+ x: _
else
{
pI2c->Cycle++; // I2C的重新启动收发作业发生错误次数值+1
gbitI2c.Error = CLEAR; // 清除“通讯收发作业发生错误”标志* C% I# T6 D$ S/ y
CommI2cBusAgain( ); // 重新启动I2C总线前一个通讯收发作业操作1 a, l$ k! R1 ]6 Q( ? K( t C
}; T! p& G/ W/ P Y( b
}
// 通讯任务时间超时计时处理,用以处理I2C总线直处于“BUSY”状态。( \3 m$ p: U. h( x5 K) T' V
if (gbitI2c.OverS == SET)
{/ N5 M, y8 l i0 |6 l
if (RtcSecByteOverflow(pI2c->OverS)) // 如果通讯任务时间计时秒表时间已溢出?- i$ D; B( V) G! p: e& T
{7 K/ O% j6 F, v5 M7 y# e
I2CCR2 = (u8)( ((0<<i2cSTART)| // 禁止 START 信号(起始条件)
(0<<i2cSTOP )|(0<<i2cACKEN)| // 禁止 STOP 信号(停止条件),使能 ACK 应答' s, ^/ j8 W$ a3 S' M
(0<<i2cPOS )|(1<<i2cRST ) ));// 应答的位置=当前字节,复位I2C模块! g( m3 P) k5 z; I9 j
CLKPECR1 &= (u8)(~((1<<clkI2C ))); // 禁止I2C外设时钟( ~) s; R& _4 V, ?* ?( t
I2CCR1 = (u8)( ((0<<i2cEN )|(0<<i2cGCEN )| // 禁止I2C模块,禁止广播呼叫& ?3 J# V2 C; T" `- I
(0<<i2cCKTEN) )); // 禁止时钟延展/ p* @! |: W6 }, u8 d
MFH_PIN_CFG_OUTH_I2cScl; // 设置I2C时钟引脚为推挽输出,并为H电平(释放 SCL)1 q& q( i6 j; s
MFH_PIN_CFG_OUTH_I2cSda; // 设置I2C数据引脚为推挽输出,并为H电平(释放 SDA)& f, e7 g' M1 c3 ~, X$ U1 M
for (i=0; i<9; i++) // 发送 9 个 SCL 时钟脉冲;在此过程中,SDA 为高电平,以复位从设备' u+ j6 _8 Q, Z6 C# n5 z0 l0 a
{4 v* C/ l3 h3 U5 p
DelayUs(1);
MFH_PIN_OUT_CLRL_I2cScl;
DelayUs(1);
MFH_PIN_OUT_SETH_I2cScl;, x' R7 S& O: Q8 m$ E4 [0 ], m' s' H
}5 C* r) L- ~( |; _) x& v; e
CLKPECR1 |= (u8)( ((1<<clkI2C ))); // 使能I2C外设时钟, f+ V) I9 R) u; ]" j" w& r- r0 v
CommI2cInit( ); // 重新初始化I2C总线" }% W8 m' v( f
}! F- @: [. A9 ~: U( n- W: \7 p
}
#endif // “PreCommI2cUseSingleMasterMode”; o, m! x( s) C2 [* U6 X
& _5 ?6 z3 ^7 z1 l; O
}
9 r, n0 E. O# b. K! a" L% j
#ifdef __cplusplus
} // extern "C" 链接指示符作用域结束# x2 R3 @9 C' e" c7 P
#endif
# K: a9 @4 l7 w
; x! }% V8 U" y, H3 `3 t5 ^
/*( P( I6 v- q5 w6 g9 ]
************************************************************************************************************
本C语言源程序文件到此结束
************************************************************************************************************
*/" i4 ^$ e" K* n3 N$ I, P% k
两线串行总线接口(I2C)
------------------------------------------------------------------------------------------------*/
// I2CCR1(I2C_CR1)——— I2C控制寄存器1" n& q" ~3 n% U/ ~% Y$ v
#define i2cEN 0 // I2C启动/停止使能位+ Z& t" l- y- e3 Y* H6 D
#define i2cGCEN 6 // 广播呼叫使能位
#define i2cCKTEN 7 // 时钟延展禁止位
, y/ C3 F& T7 i; O4 Z3 r/ U* {
// I2CCR2(I2C_CR2)——— I2C控制寄存器2) i- b- u( }, T# [
#define i2cSTART 0 // 起始位状态 B; [1 V& _: M1 n
#define i2cSTOP 1 // 结束位状态
#define i2cACKEN 2 // 应答使能位
#define i2cPOS 3 // 应答的位置- f9 R, ?( ~6 n5 Z
#define i2cRST 7 // 软件复位
- T( J) B0 x- D" @" V. s
// I2CARL(I2C_OARL)——— I2C(从机)地址低位寄存器+ j: w( E. A2 P! ^/ h
#define i2cADD0 0 // I2C从机地址位0
#define i2cADD1 1 // I2C从机地址位14 o4 \+ L8 O! h! U
#define i2cADD2 2 // I2C从机地址位2, E8 f7 U& f- ~; _
#define i2cADD3 3 // I2C从机地址位3
#define i2cADD4 4 // I2C从机地址位4
#define i2cADD5 5 // I2C从机地址位5/ V, U' e( `; k R6 }: V, B& t
#define i2cADD6 6 // I2C从机地址位6$ `% \% x. Q$ t4 ^" U/ w' v) j! Q
#define i2cADD7 7 // I2C从机地址位7# e( M5 Z( ?" A* k9 D* n, E4 S
#define i2cADD17 1 // I2C从机地址位1~7
9 k- V: x5 X ]0 x) a/ k
// I2CARH(I2C_OARH)——— I2C(从机)地址高位寄存器
#define i2cADD8 1 // I2C从机地址位8
#define i2cADD9 2 // I2C从机地址位9& X3 V. k0 g/ H! T
#define i2cCFG 6 // 地址模式配置
#define i2cMODE 7 // 寻址模式
#define i2cADD89 1 // I2C从机地址位8~94 W- {* n5 G" b
! k7 T6 A) Z5 K; m3 e: m1 Q
// I2CSR1(I2C_SR1)——— I2C状态寄存器19 Y1 p- [& H: L a6 A: k( P3 a. T
#define i2cSTAF 0 // 起始位(主模式)
#define i2cADDTR 1 // 地址已被发送(主模式)/地址匹配(从模式). \/ }7 {+ g5 o2 \8 l" j) J, |
#define i2cTXC 2 // 字节发送结束
#define i2cADD10 3 // 10位头序列已发送(主模式)2 N) y7 B$ B B# q
#define i2cSTODF 4 // 停止条件检测位(从模式)# n! `2 P* f2 k A/ {! T4 R9 g
#define i2cRXNE 6 // 接收数据寄存器非空
#define i2cDRE 7 // 发送数据寄存器空3 o- R9 P) w) ^4 f. m" H
// I2CSR2(I2C_SR2)——— I2C状态寄存器2
#define i2cBERR 0 // 总线错误+ x, E+ N! V7 c; Y4 }8 |
#define i2cARLO 1 // 仲裁失败(主模式)) g( p* q1 m2 u g2 R, e. E
#define i2cACKF 2 // 应答失败$ _) @ ? q2 }8 E& k# v
#define i2cOVF 3 // 溢出标志位
#define i2cWUF 5 // 从停机(Halt)模式唤醒标志
// I2CSR3(I2C_SR3)——— I2C状态寄存器37 s0 Z7 g+ U( G
#define i2cMSF 0 // 主/从机模式标志位
#define i2cBSY 1 // 总线忙标志- I+ V5 w& u7 U+ K2 T. B
#define i2cRXTX 2 // 接收器/发送器,0:接收,1:发送4 Z* @/ a5 Q6 M' U( }
#define i2cGCF 4 // 广播呼叫头序列(从模式)+ g7 v: N3 G& H3 F
& ?" ^# h O% D$ ]0 W. h8 n1 C
// I2CICR(I2C_ITR)——— I2C中断控制寄存器; [/ u6 v7 s9 a% m
#define i2cERRIE 0 // 错误中断使能位
#define i2cEVTIE 1 // 事件中断使能位1 {& V2 r* _; D# p2 a* g) e( ?
#define i2cBUFIE 2 // 缓冲中断使能位- G2 x! s9 I8 J0 g
$ z, W9 P$ s1 h* c2 l1 [- u% H: v
// I2CCCRL(I2C_CCRL)——— I2C时钟控制低位寄存器
#define i2cCS0 0 // 预分频器时钟选择位0
#define i2cCS1 1 // 预分频器时钟选择位1$ c% y7 f2 z( W, b0 t$ p: W
#define i2cCS2 2 // 预分频器时钟选择位2- K1 O: w- \0 `8 W
#define i2cCS3 3 // 预分频器时钟选择位3
#define i2cCS4 4 // 预分频器时钟选择位4
#define i2cCS5 5 // 预分频器时钟选择位5- c$ i8 _ N& p# k9 T1 g" d
#define i2cCS6 6 // 预分频器时钟选择位6
#define i2cCS7 7 // 预分频器时钟选择位7
// I2CCCRH (I2C_CCRH)——— I2C时钟控制高位寄存器, r% R2 O) J7 A* q
#define i2cCS8 0 // 预分频器选择控制位82 `& ~& S+ ^# H8 D& S( A
#define i2cCS9 1 // 预分频器选择控制位92 C, `: g# D/ O. V# M0 o1 j1 ~7 g
#define i2cCSA 2 // 预分频器选择控制位10
#define i2cCSB 3 // 预分频器选择控制位11
#define i2cDUTY 6 // 快速模式下的占空比$ F+ ~; t! _# ?8 N$ t' s7 A
#define i2cSFM 7 // 标准/快速模式选择位
__IO_REG8_BIT(I2CCR2 , 0x5211, __READ_WRITE, __BITS_I2C_CR2 );// I2C控制寄存器23 L0 c$ z* G7 Q S2 g/ V& c \
__IO_REG8_BIT(I2CFR , 0x5212, __READ_WRITE, __BITS_I2C_FREQR );// I2C频率寄存器
__IO_REG8_BIT(I2CARL , 0x5213, __READ_WRITE, __BITS_I2C_OARL );// I2C(从机)地址低位寄存器
__IO_REG8_BIT(I2CARH , 0x5214, __READ_WRITE, __BITS_I2C_OARH );// I2C(从机)地址高位寄存器# f5 }% n4 G; C0 ]) ]" N
__IO_REG8 (I2CDR , 0x5216, __READ_WRITE );// I2C数据寄存器
__IO_REG8_BIT(I2CSR1 , 0x5217, __READ, __BITS_I2C_SR1 );// I2C状态寄存器1
__IO_REG8_BIT(I2CSR2 , 0x5218, __READ_WRITE, __BITS_I2C_SR2 );// I2C状态寄存器2
__IO_REG8_BIT(I2CSR3 , 0x5219, __READ, __BITS_I2C_SR3 );// I2C状态寄存器3
__IO_REG8_BIT(I2CICR , 0x521A, __READ_WRITE, __BITS_I2C_ITR );// I2C中断控制寄存器8 y; \. R4 t& u" D# h
__IO_REG8 (I2CCCRL , 0x521B, __READ_WRITE );// I2C比特率低位寄存器* c7 K D( E' M# a3 g% n4 |; ^9 T
__IO_REG8_BIT(I2CCCRH , 0x521C, __READ_WRITE, __BITS_I2C_CCRH );// I2C比特率高位寄存器- m* B: t5 `) g( M: j
__IO_REG8_BIT(I2CTRISER , 0x521D, __READ_WRITE, __BITS_I2C_TRISER );// I2CTRISE寄存器
__IO_REG8 (I2CPECR , 0x521E, __READ_WRITE );// I2C包错误检查寄存器
case cI2cMrxAddrAck: // SLA+R 已发送,接收到 ACK' h6 P' j3 C- v( c
{ E2 Q1 L+ u5 k; H* U# C; V
MFHI2cBusRdataAck( ); // 在接收之后发出 ACK 脉冲 f( e& y$ q! R# L/ M: _) ]& w% ^
MFHI2cIntEventOnn( ); // 使能缓冲中断
break;
}/ u/ I5 i9 W, L3 |3 Z7 T2 ~* `
改为:
case cI2cMrxAddrAck: // SLA+R 已发送,接收到 ACK( P. ~/ ?. ?7 U, |
{
if (pI2c->RxSize <= 1) // 如果只接收1个字节?% M- r" Q6 `% r9 @
{. L0 V' ~, n3 l6 E! x/ ^$ J% [
MFHI2cBusRdatNack( ); // 在接收之后发出 NOT ACK
MFHI2cBusNackStop( ); // 发出 STOP 信号(结束条件),没有 ACK 脉冲
}% ^7 Z1 K: y4 M( o% w
else
{
MFHI2cBusRdataAck( ); // 在接收之后发出 ACK 脉冲
}4 S( b* }( u- ?7 ]3 l
MFHI2cIntEventOnn( ); // 使能缓冲中断( J1 q7 _6 a, D& G, C- Y
break;. L) G% b7 I9 X- c5 ^: @* ]
}
以避免只接收1个字节时,发生溢出错误。