你的浏览器版本过低,可能导致网站不能正常访问!
为了你能正常使用网站功能,请使用这些浏览器。

基于一块测线板,让你从STM8S从入门到提高  

[复制链接]
w453509596 发布时间:2015-1-8 21:14
本帖最后由 w453509596 于 2015-1-9 13:01 编辑
9 [# o% N( Q) U0 s: k2 F% {9 h* O" {- |: l. U& H. l8 r0 A* g
    我刚刚使用STM8S几个月,从刚开始到现在会使用,在这过程中也走了很多的弯路,浪费了许多时间。我看到也有一些刚接触STM8的同学和我刚开始一样,对于入门STM8无从下手。我在这里把我入门的过程给分享出来,希望能对想入门STM8S的同学有所帮助。根据我个人的学习经历,感觉初学者最需要的是从一个实际的项目入手,让初学者在不熟悉其全部理论的情况下也可以把东西做出来,然后再回过头来去理解其中的全部原理。我的STM8入门是从一个测线板开始的,我把我的学习过程和其中碰到的问题全部写了来。
+ H5 M. R' |+ y- Z$ |+ S   1 准备工作: 一块STM8学习板,编程软件,数据手册,参考手册, 一颗坚不可崔的决心。
, E- O$ D- O, F3 b   想做成一个东西,兴趣、压力、动力,这几点非常重要,我希望朋友们在学习STM8之前能给自己找一个学习的理由,绝对会事办功倍,我当初给自己设了一个理由,我学会了STM8S,就能够涨工资,然后就可以找到个漂亮的女朋友。学习STM8有着他天然的优势,首先这芯片价格便宜(香蕉超市最便宜卖2块2,它最便宜的只要1块5);其次,学习它只需要用到我们最喜爱的语言(chinese Simple);再次它的官方资料非常多,官方库的程序很直观,不像飞思卡尔什么的,各种秀操作。最后还有我们这个强大的社区  (https://www.stmcu.org.cn/)。我当时的资料全部都在这个社区找的。
+ {6 P$ k6 s% s6 g9 P0 p
) V5 I& J0 [) q4 o8 \: y4 H
8 d% Y3 s, X+ G6 [4 t# _
赞 收藏 5 评论44 发布时间:2015-1-8 21:14

举报

44个回答
w453509596 回答时间:2015-1-8 21:56:18
本帖最后由 w453509596 于 2015-1-8 22:22 编辑 - R5 z* G2 Y( g3 x9 j5 n/ `% Q
! c5 l5 s5 b+ k- _  h; {8 T
首先编程软件的安装,开发环境的搭建,以及想自己建立工程模板的同学们,请参考附件。我在这里介绍如何驱动我的板子上面的LED。 - K5 ^8 N4 p* C3 d7 o! e
  从原理图上可以看出,我的8颗LED连接PG0~PG7上面,公共端连接在ULN2003A上,由PE0端口驱动。如果我想要第 1 个小灯点亮,只要 PG = 0x01 , PE0 = 1 即可。# `: t! q6 D8 |% v" `5 @/ M/ f. A
  如查想做个LED的闪烁效果,大家可以在MAIN文件中加上如下一段简单的程序" D3 P6 _/ _; D) L& L. e

8 X$ }9 s5 j) Q( W# Hvoid delay(unsigned int t)   
( c  w6 f: l+ e* M1 J{- k# U! {* U1 i: Z$ t$ i( Y
  unsigned char i;
+ L; X/ e$ q& D9 H) E  while(t--)
- }8 J. F1 z& k$ B; E8 y* N& k  {( S7 y8 I1 Q! `# L; l
    for(i=0;i<250;i++);0 i8 S. ~; N* v$ A+ }2 g6 ?8 {
  }/ L9 b* E0 r  p/ T; Y/ _3 ^
}
. I# J3 K7 G- P- c, _) ~4 |+ w# g5 q# G; _
void main(void)1 A. W2 q  F3 K& A
{
. e/ [  n2 D: x0 b) L   GPIO_DeInit(GPIOG);  //复位G端口寄存器7 q8 R& A* s1 P$ b* W
   GPIO_DeInit(GPIOE);  //复位E端口寄存器
9 k; K4 I* i5 _   
0 P7 V) O2 K& @6 `( r, J4 R   GPIO_Init(GPIOG,GPIO_PIN_ALL,GPIO_MODE_OUT_PP_LOW_SLOW); //初始化GPIOG为推挽 低速 输出
8 `8 a9 r" s' k2 C! C                                                                                                                //初始电平为低电平
, b- H$ K( H3 X) N7 M- `. o8 [7 L   GPIO_Init(GPIOE,GPIO_PIN_0,GPIO_MODE_OUT_PP_LOW_SLOW);   //初始化GPIOE0为推挽 低速 输出
6 ?. {+ B# K9 K0 P8 y, j, z: z                                                                                                               //初始电平为低电平
7 N  f, Z, Q  g6 U: d& U5 e   ' [0 L6 R) q; u& u) P8 R' D4 ~
   GPIO_WriteHigh(GPIOE, GPIO_PIN_0);   //打开LED的公共端  即 PE0 = 1
5 `; M+ Y! s+ t* T) u9 R  /* Infinite loop */
: T; {* f' j1 @2 M& H! Q$ @  while (1)
9 F+ [3 J! e) {0 B# y4 h* q! w  {9 d7 g% O: ]8 k/ k, u9 @
    GPIO_WriteHigh(GPIOG, GPIO_PIN_0);   //点亮第1个LED   即PG0 = 1
- ~5 M- a5 A3 T& N, u, e# b    delay(1000);                                          //延时一小段时间% i+ ~2 j- G/ B( y( ~& c
    GPIO_WriteLow(GPIOG, GPIO_PIN_0);   //关闭每1个LED   即PG0 = 0
7 u8 S( t; J* a( R; G    delay(1000);                                          //延时一小段时间
; ~5 }6 i- {; K+ I" k6 B3 P# J  }
8 C6 ?) ]/ O' }6 @, X2 c5 S0 N}
- t& Y2 Y) y3 _3 h( @/ ^8 S" j% A4 A4 M! C2 r+ U0 Y
在这段程序中,单片机使用的是上电复位后默认的初始化(内部16M的参考时钟8分频,即2MHz作为系统主频)。
& I& ]6 G+ p2 B  x, B' m+ G  J3 V% S1 F9 k
GPIO_Init(GPIOG,GPIO_PIN_ALL,GPIO_MODE_OUT_PP_LOW_SLOW);函数的原型如下
0 W. J/ V2 F- Cvoid GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin, GPIO_Mode_TypeDef GPIO_Mode)
& y2 L: T$ Z3 M+ u它的功能是初始化一个端口的指定引脚为某种状态' Q: F) ]" S. O, n

4 `) Q' u3 K& H这个函数它有三个参数, * o! ]; m& l  {7 ^
第一个 GPIO_TypeDef*   GPIOx    ( 选择端口)' w6 e* w# [6 z0 P! C
其中这个 GPIOx   可以替换成 GPIOA 、 GPIOB、 GIPOC、GPIOD、GPIOE、GPIOF  t. H. D4 b$ `% Z7 Y" c) \' k
$ H9 p5 |9 {$ W" }: @/ b' S
第二个参数是  GPIO_Pin_TypeDef   GPIO_Pin      (选择引脚)  
' s- \! R  H+ Q- f2 X其中这个 GPIO_Pin 可以替换成下面这些: k2 ?5 @4 f( }% _0 b/ E( i3 a
  GPIO_PIN_0    = ((uint8_t)0x01),  /*!< Pin 0 selected */2 N9 i1 O6 f6 L' I/ F
  GPIO_PIN_1    = ((uint8_t)0x02),  /*!< Pin 1 selected */7 `! Q, |5 }- D% Q5 }, s
  GPIO_PIN_2    = ((uint8_t)0x04),  /*!< Pin 2 selected */
+ G/ M# W* ]& h  GPIO_PIN_3    = ((uint8_t)0x08),   /*!< Pin 3 selected */
7 ~4 O- k1 x7 U  GPIO_PIN_4    = ((uint8_t)0x10),  /*!< Pin 4 selected */$ g9 {1 y- b) M+ n2 o/ @. A
  GPIO_PIN_5    = ((uint8_t)0x20),  /*!< Pin 5 selected */8 m7 B+ y) w) e' m! O6 q
  GPIO_PIN_6    = ((uint8_t)0x40),  /*!< Pin 6 selected */+ M1 K1 t. h% x. H) i
  GPIO_PIN_7    = ((uint8_t)0x80),  /*!< Pin 7 selected */
0 @. d* H$ S. G* f# D  GPIO_PIN_LNIB = ((uint8_t)0x0F),  /*!< Low nibble pins selected */
8 y' f  d5 e/ [; r  GPIO_PIN_HNIB = ((uint8_t)0xF0),  /*!< High nibble pins selected */" k: u0 t/ s5 x/ p
  GPIO_PIN_ALL  = ((uint8_t)0xFF)   /*!< All pins selected */
" _- k* x, A, [6 D* @' Q- ?% Y. o2 }  |
第三个参数是  GPIO_Mode_TypeDef   GPIO_Mode  (选择模式)
9 |6 [9 a' \- F6 x+ `( V" J- p; H其中这个 GPIO_Mode 可以替换成下面这些
1 T! m" l) M- ^GPIO_MODE_IN_FL_NO_IT      = (uint8_t)0x00,  /*!< Input floating, no external interrupt */0 `- h% P. F5 s
  GPIO_MODE_IN_PU_NO_IT      = (uint8_t)0x40,  /*!< Input pull-up, no external interrupt */
! R5 g1 d- U6 s1 ]  z: u6 B4 H  GPIO_MODE_IN_FL_IT         = (uint8_t)0x20,  /*!< Input floating, external interrupt */$ N: u9 [/ g, T9 L
  GPIO_MODE_IN_PU_IT         = (uint8_t)0x60,  /*!< Input pull-up, external interrupt */$ w  h# ]: B  @$ W+ o
  GPIO_MODE_OUT_OD_LOW_FAST  = (uint8_t)0xA0,  /*!< Output open-drain, low level, 10MHz */
8 u* Z( T4 o5 G" u1 y  GPIO_MODE_OUT_PP_LOW_FAST  = (uint8_t)0xE0,  /*!< Output push-pull, low level, 10MHz */
# r$ e0 d% f( W) d# E0 \/ R/ [  GPIO_MODE_OUT_OD_LOW_SLOW  = (uint8_t)0x80,  /*!< Output open-drain, low level, 2MHz */" t# o4 V  Z( B" J- ?
  GPIO_MODE_OUT_PP_LOW_SLOW  = (uint8_t)0xC0,  /*!< Output push-pull, low level, 2MHz */; p6 ~8 z' G+ g& W# L7 S
  GPIO_MODE_OUT_OD_HIZ_FAST  = (uint8_t)0xB0,  /*!< Output open-drain, high-impedance level,10MHz */
1 G! x/ e: L) {1 y  GPIO_MODE_OUT_PP_HIGH_FAST = (uint8_t)0xF0,  /*!< Output push-pull, high level, 10MHz */
  w4 @+ m5 Z% V, \  GPIO_MODE_OUT_OD_HIZ_SLOW  = (uint8_t)0x90,  /*!< Output open-drain, high-impedance level, 2MHz */
" J4 _. j( a1 p8 x/ _  M  GPIO_MODE_OUT_PP_HIGH_SLOW = (uint8_t)0xD0   /*!< Output push-pull, high level, 2MHz
4 e# N6 \" G+ W6 X1 C4 Z9 {5 X7 X8 B( S4 a# r  |  L9 y, M
4 H) Z* Z, @9 G) g  }) O* p
GPIO_TypeDef 是一个结构体类型 ,它的定义如下: (这个对于初学单片机的同学可以不用关心)' ?$ f) S& r% y( ^6 o: }+ e
typedef struct GPIO_struct
7 _& o6 m1 L! [{, s4 j2 m1 n6 c9 m# |: v
  __IO uint8_t ODR; // 数据输出寄存器
  a: Z$ Z, [% h( P( X' O8 n. a  __IO uint8_t IDR; //数据输入寄存器$ d5 K9 w- O! K+ y
  __IO uint8_t DDR; //端口方向寄存器  
. y( f" p# J0 d% x0 y2 M( `# b  __IO uint8_t CR1; //控制寄存器1
# s5 A8 t! Y7 S- r7 u. ?5 b# B; o  __IO uint8_t CR2; //控制寄存器2) b0 @+ G8 p* B4 e8 t6 `5 e6 ~, E* k
}5 H- s3 a5 ?0 s1 i( {
GPIO_TypeDef;5 i7 d; |4 |- v, ~0 S- p6 S0 B4 h

% h2 y; P3 D/ [#define GPIOA ((GPIO_TypeDef *) GPIOA_BaseAddress)   //这里是为从 GPIOA_BaseAddress 到  GPIOA_BaseAddress + 5 这段地址                                                                                                 //取个名字叫GPIOA  ,STM8所的寄存器都是差不多这样定义的
0 ]4 `1 m; a  s3 q7 p: [#define GPIOB ((GPIO_TypeDef *) GPIOB_BaseAddress)3 e+ q0 f+ y9 s+ r( K, Y: P6 B  H
#define GPIOC ((GPIO_TypeDef *) GPIOC_BaseAddress)
/ t6 X/ \. f  j3 k) Y4 D#define GPIOD ((GPIO_TypeDef *) GPIOD_BaseAddress)- k9 o% t( B" {4 {$ |! R& y
#define GPIOE ((GPIO_TypeDef *) GPIOE_BaseAddress)" E# L+ r+ j2 m" r" S
#define GPIOF ((GPIO_TypeDef *) GPIOF_BaseAddress)( @, ~% \8 B2 H  N5 L8 O" n
4 Z: |" Z8 Z9 z- M
; M  Z% |1 O* q* k9 d
' P0 L5 j- A1 |8 t) n
: t9 G  U9 c/ j! m$ a+ ]- z
1 O$ t, ^3 v1 L$ ?

1 [' J8 ~8 y4 U4 p( y4 S( q+ z/ e/ {; `8 p

$ A, o5 t& f, j$ n1 h
' p) w+ d2 ?2 e, o) m+ F) z: Y
0 d2 o- q  E, ?  x! q. d) k
7 K" @# h8 Z& {' U% M& `9 N6 r

LED.rar

下载

351.84 KB, 下载次数: 70

示例程序

2-开发环境搭建.pdf

下载

614.44 KB, 下载次数: 110

搭建开发环境

3-如何使用库来创建自己的工程.pdf

下载

809.16 KB, 下载次数: 127

建工程模板

5-LED(GPIO).pdf

下载

500.56 KB, 下载次数: 75

风驰的教程

w453509596 回答时间:2015-1-9 13:17:58

基于STM8S的外部I/O 中断 红外遥控解码

本帖最后由 w453509596 于 2015-1-11 10:48 编辑
6 z) G% u* b8 A# Q  q' l
: B/ A. K/ t, m4 w4 }2 j基于STM8S的红外遥控功能。我给大家分享一段代码。由于是产品了,不上传全部程序了( j9 g, \' Z! b( N& m( [
FuncState InfraredWate_Flag;  //等待按键松开标志
. ?3 ?$ s9 M% F+ }4 Y8 RUint8 InfraredWate_Index;     //用于等待按键松开计时6 e7 q0 n" q) ?  ?! \, G
FuncState InfraredRec_Flag;   //红外采集完成标志
) a: O4 c* Z! @Uint8 InfraredCode;           //红外接收代码
3 W9 n% w! p) f2 P& k, KUint8 InfraredCode_Index;     //红外接位计数
- v* c' k4 V% v! E& d) Q" SUint8 InfraredBuffer_H;       //红外识别码接收缓存9 B, K$ E+ _$ i2 n# r9 J3 K
Uint8 InfraredBuffer_L;       //红外接收代码缓存
4 k0 j+ O, _1 I, XUint8 InfPeriod_Status;       //红外周期状态& V4 a1 W( d3 j& L  F+ G" j, Y
Uint16 TimeCounterVal;        //计数器临时值
5 ]1 k2 b! V; e8 U' ~2 ?0 SUint8 ReciveIndex;            //红外接收计数
# t2 _4 K! k: f5 f# o# u( [5 w" p$ e2 s( ?6 ~  n
static void TimeCounter_Start(void)    //启动计数# r  l, C4 P3 I; T4 D
{
% e# G, y, j5 _- x- G) U! F    TIM2->CNTRH = 0;
  H( v2 s3 f, T) I    TIM2->CNTRL = 1;$ ~  r6 h* i, X" u
    TIM2->CR1 |= 0x01;* W9 v& O- m3 V& {5 k
}
! ^+ N  }! J' j# \
0 k7 T. ?: W8 K: c* @3 L2 x& bvoid TimeCounter_Stop(void)    //停止计数
6 \. j# ?0 i6 O$ n; }{" ]5 a) Z" z) p; @
    TIM2->CR1 &= 0xfe;, k/ f# \; ?* y4 b! N
}$ d- J1 P2 D1 k2 y2 h& I& W0 m
6 r& u$ @& N) H
static void InfraredRec_Bit(Uint8* BufferAddr)
0 T8 n! s$ }  F$ ~$ S{
; N  m9 S2 Q( L7 `   if((12000 < TimeCounterVal)&&(TimeCounterVal < 22000))    //0周期约为17000- j0 }9 I* r4 D* K5 ?, I- G( U
   {5 y) m# K9 ?2 \9 X
     *BufferAddr = (*BufferAddr) * 2;
2 w& W0 Z) {3 @5 o( {* S   }% z$ a4 Y2 h$ e/ k
   else if((30000 < TimeCounterVal)&&(TimeCounterVal < 40000))  //1周期约为350003 F- ~( N) P$ n. ], T% C4 |
   {. t6 |- D, `) z/ [) F
     *BufferAddr = ((*BufferAddr) * 2) + 1;
& ~1 w3 n2 s. R: X4 T* u   }$ i, m4 K) i2 j/ Z$ W- M8 v$ V
   else ReciveIndex = 0;0 A. d& ~9 Q8 O0 Y
}0 Q9 b1 M2 |1 H+ n* j

7 ^& w% q/ m$ A( E  w: O  {void InfraredInterrupt_Process(void)5 m; r0 R. Q! m3 A: B7 t
{3 J4 n) G0 y/ Y! u1 U) e
  if(InfraredWate_Flag != L_FASE)       //等待接收到按键松开的间隔符,才开始下次接收  每次中断4ms,10次约40ms
, M$ [, _: P- t* o9 q0 i$ P* U  {* C2 I$ e( z# Q% M, ~# ^0 _
    if(InfraredWate_Index <10) InfraredWate_Index ++;  
' v9 H5 F6 ?! |6 N* A( \1 x8 z5 e0 x    else
: O$ r; Q2 B: b: I    {9 @3 _& ^; A% Z4 [9 E
      InfraredWate_Flag = L_FASE;                                   //已等到间隔符,清标志位      
$ h6 W! o" C" I) M4 z: ], k% n$ d2 I      TimeCounter_Stop();  + U& E: u8 d, g+ S+ U
      InfPeriod_Status = InfPeriod_Start;  s& n- E7 C; y
    }3 |5 m, Z( k2 D
  }6 T5 _% `5 i# K1 J1 ^$ E/ O
  else                            //防止计数中间产生的,错把间隔符当成正常位。还有一种是由于排除红外不工作时产生的干扰。9 Z1 \& U4 l4 g& I$ K) i: `0 e, v
  {0 ^! p: N9 f3 o5 P4 o
    TimeCounter_Stop();' H+ }% S# I: l$ B+ {6 k
    InfPeriod_Status = InfPeriod_Start;" W% n& `' Q0 V0 L0 W6 E) x* f& {
  }0 O" e2 G( x; {, @: S3 G
}( {1 Q5 Q  s- g% m1 S

; ]% C) p+ i  P, a' Bvoid PeripheralInfrared_Receive(void)
1 Q2 J6 b; i5 Y! e{
% j. C7 L8 G1 \# ^! M! B. }- v  if(InfraredWate_Flag == L_FASE)                            //处于非等待间隔符状态,开始正常接收  
/ X+ i3 h6 [, b% Z: m2 H1 P/ Y  {5 y: _2 i6 r, i
    if(InfPeriod_Status == InfPeriod_Stop)                   //开始接收数据1 z# N6 H* H; `5 S
    {1 C' @4 c& \8 u6 z+ H6 Z
      disableInterrupts();4 b% y7 h: O- ]; f0 j, h% z3 |& }
      TimeCounterVal  = ((uint16_t)TIM2->CNTRH << 8);! q( m8 O& V; |! j$ T+ Y
      TimeCounterVal |= (uint16_t)(TIM2->CNTRL);
0 F. u, x! f& a* V7 k/ E      TimeCounter_Start();0 k) }% D0 T7 ?3 M
      enableInterrupts();                                //存在一些硬件上的互锁机制,为了使得数据更准确,这里关掉中断,防止其它干扰
; Z( D6 b4 R) B9 J& C7 j      & p% G9 ~8 b# {  S: t/ }
      ReciveIndex ++;! o% c0 i+ r  U" `7 @) P
      if(ReciveIndex <= 8)  InfraredRec_Bit(&InfraredBuffer_H); //前8位数据
) n* W- X. Z6 L2 U& z. V" i3 }      else  InfraredRec_Bit(&InfraredBuffer_L);                 //后8位数据               
* u; s8 P* O2 }& d( q      if(ReciveIndex >= 16)
% U6 S5 ]9 y: X1 ]- }      {+ n, H  d2 c5 n' U( O$ |3 x
        InfPeriod_Status = InfPeriod_Start;( R) h5 O8 ^" I
        if(InfraredBuffer_H == InfraredUser_Code)   //如果识别码正确
% c, f4 i: {; Q) p        {5 k0 J8 ~5 K4 p9 F
          InfraredWate_Flag = L_TRUE;               //已接收到功能码,等待间隔符
: C% v8 S7 l  U. M' `          InfraredWate_Index = 0;) S6 |+ d+ z: Z1 n+ @9 I4 g( Z3 n
          InfraredRec_Flag = L_TRUE;               //
9 j& [7 p2 G0 Y, r# `          InfraredCode = InfraredBuffer_L;         // 将数据送入缓存区  
! e6 M8 y( [* t/ R5 @; z        }. S: F- y" F  N0 V* S1 ~
      } / E# w& |/ z" w' ]
    }
7 C% O) r2 }, _0 l% C. V    else                                      //如果接收到了启始符,置标志位,开始接收数据
- Q0 {3 {% c- k' A8 o* _    {8 [" |8 Y; `. V- D. Q6 i( S1 D) }
      TimeCounter_Start();
1 d9 U& Y8 h# U- A      InfPeriod_Status = InfPeriod_Stop;
: M5 b6 S1 t. r1 b      ReciveIndex = 0;
2 }3 ], F( g. b# x8 w- i; |    }
% a$ `+ Q$ w; r
: m2 N3 Q: H/ {  }0 d; F# p7 {# k3 M/ H: z% N2 y
  else InfraredWate_Index = 0;                //在等待按键松开,理论上讲,是不允许再接收重复红外信号的
' w8 X# l7 ?9 @' q% ^: V}https://www.stmcu.org.cn/module/foru ... &pid=2049512&page=1: K, M- y' n7 V# F' J6 X0 k$ S

/ b' @7 @) J& i  rvoid Infrared_InitVar(void)/ @9 t* ^7 o; R9 g; n
{
( @' p2 b1 m2 k- L- s  InfPeriod_Status = InfPeriod_Start;
4 p: }0 x+ k1 z" t1 S" F  TimeCounterVal = 0;2 X* |) z* L0 E  R; X  T0 @5 p  b
  ReciveIndex = 0;
0 g0 J0 m+ I1 r1 ?2 e9 R! V* |  InfraredBuffer_H = 0;
/ j% S) b, H- @5 t  InfraredBuffer_L = 0;2 [8 `7 U9 ?& F6 x) `3 p8 l6 ?
  InfraredCode = 0;: l% b) K- n4 ?. \0 ]+ t
  InfraredCode_Index = 0;% m  `& Z$ f- c
  InfraredRec_Flag = L_FASE;' l' T0 g( c7 |/ }% @1 y' r$ b
  InfraredWate_Flag = L_FASE;) m% b9 f% B- ^5 A" s
  InfraredWate_Index = 0;
3 D% k4 ~5 V/ h. m. f9 n}
; F! l0 o6 p9 I: [
+ j* Z. a3 I8 z' s' g* ~5 J
3 }: @! i' S3 l6 a在这个红外编码中由16位组成一串字帧。0 由 0.26ms的低电平和0.8ms的高电平表示, 1由 0.26ms的低电平和1.8的高电平表示。" n% Y1 f" I- a& y
两者的周期相差一倍,我把红外信号由红外接收头HS3818接收后送到STM8S的外部中断I/O上面,我是根据数据周期来判断是0: t1 ]( n2 s* L- b1 _% H
还是1的。
. U* R  i7 v7 B6 S" w1 C2 R! i5 k
w453509596 回答时间:2015-1-8 21:59:40

STM8S按键驱动

本帖最后由 w453509596 于 2015-1-9 11:30 编辑 ; ^- ?% P; z" E1 e, E* }7 j1 S

2 E; K9 c: Y, w- ?$ n$ {: B     按键分为独立按键和矩阵按键,矩阵按要比独立按键省I/O口,但是驱动程序要复杂。这两者各种有利有弊,那么有没有两者兼得的方法呢。如果的你的工程中有段式LED的话,恭喜你中奖了,看看我的方法吧。* ?+ {9 M" S9 `5 R
    从我的测线板的原理图中可以看出,我在不增加I/O的情况下,让我的测线板多上了8个独立按键。那么如何驱动这8个独立按键呢。以前学
8 J. j6 d5 @% s( J的都是,先判断到有按键按下,再等10ms,如果按键还是按下的,则置下按键按下标志。那么问题来了,10ms的延时(不符合节约的原则),还有
0 C1 f. c# n: J如果我的按是长按的怎么处理呢。我分享下我的方法。我也是在中断中处理的。4 R* N: R- ?, b
    我会为什么时候执行显示,什么时候处理按键检测 排个次序。有点类似操作系统中的分时复用。现在把执行按检测的部分独立起来看。
  p, f# n+ Y3 m, ]" `; f    每次执行按键检测的时候,我会先判断8个按键的状态,看看有没有被按下,如果没有,则不用理会。如果有,则记下一标记,下一次时中断,还6 O6 V' b8 V2 L' t# E7 O3 Z
有按下,那好了,程序就认定有按键按下了,接下来的连续几次进中断,还是有按下,则认定它为长按了。我附上我的程序。8 |* O7 E6 ?) R  i

# z$ C: m- D* x$ Y: ~4 U2 I# X3 M0 M4 D
KEYStatusDef KEYStatus;     //按键的状态 分为三种: 没有按下;   已经按下了,等待下一个中断确认; 等待按键松开,或确认为长按) z' ^& o0 _, t% e$ R6 e! i
KEYValueDef  KEY_Value;
7 p( Q4 V, c4 q2 W! V3 F* o7 x  z2 c6 jFunctionStatus KEY_Flag;
6 ?' \" B( q9 Z* R5 v- Ustatic Uint8  KEY_Temp1;
3 y" `( L4 m% Zstatic Uint8  KEY_Temp2;
! F) T3 l0 S+ Y* D0 m7 S9 n* W% Y; C
static void KEY_PortScan(void)   // 从没有按键按下到按键的确认
. Z/ D1 g# @% n: C( K5 R3 Z{
( U( f7 d: ]1 V* I7 @  KEY_Temp1 = KEY_Data;& D% l9 ^4 y/ z
  if(KEY_Temp1 != 0xff)
5 l1 V; s$ Q/ R1 N  `% l( ?  {   & Y8 a; g; c6 p4 r) Q7 b9 r5 ~
    KEYStatus = KEYStatus_Ok;6 {5 l5 w+ V$ y( ^& b: U: X9 g
  }$ K( _: }+ E( i5 r
}
4 S1 O# @  M- O+ U8 E* F" a  z
* S+ W( D( x1 z, [$ B$ Cstatic void KEY_PortOk(void)      //从确认按键下到等待按键的松开
* C4 a: [. k  {" S& L{3 K: ^8 `# E  f  U0 Q1 @
  KEY_Temp2 = KEY_Data;
4 t) M+ a: d. u; k9 L  if((KEY_Temp2 == KEY_Temp1)&&(KEY_Temp2 != 0xff))   //再次判断按键,如果值和上次相同,则认定有按键按下
8 }8 D$ c' S( F! b+ |( x) N, e0 K  {& Z$ r" J, x9 N( z& p7 [6 U2 w5 s  b
    KEY_Value = (KEYValueDef)KEY_Temp2;         //保存按键值" p& v% C0 J- j  K$ b
    KEYStatus = KEYStatus_Pro;
5 G% n0 n8 }. z) i9 |    KEY_Flag = L_TRUE;                                      //置按键按下标志位3 a# l5 V# c; ]  j
  }else KEYStatus = KEYStatus_Scan;   
7 Q: I6 c- U0 ]0 k! r}
+ W$ K0 ?5 \6 \  [- n% q" W5 Y" ~: Z- q8 R9 K3 e3 J5 Y( p
static void KEY_PortPro(void)      //判断按键的松开,去检测下一个按键的按下: M" V; j. N; V) G# e
{
: @( m: }: U* e! H; ^$ g  KEY_Temp1 = KEY_Data;
& R9 c* N  Q8 A* J  if(KEY_Temp1 == 0xff) KEYStatus = KEYStatus_Scan;
4 I7 p$ g, ~0 k% e  else /*判断按键 长按*/
7 `5 [. ^4 d( p5 c5 ^4 d8 |' |% V}( |' H3 ~7 `7 Z& S) Q
, G3 n; g% g! v: Y
static void KEY_Scan(void)
, e, @, Y% b/ B& o! W{; H: M6 Z$ ^+ t0 m! I* z* B
  KEY_Input();                 // 置I/O为输入端口,用来检测按键输入功能. [* w/ @9 j+ _' s8 k+ b8 o' E; V
//在主频比较大时,内核的处理速度大于I/O的处理速度,因为I/O最大输出速度只有10M,输入更低。STM8S最高主频有24M,这里加空操作,数量按实//际测试而定,我为工程的稳定性,很保留的加了10个nop();,5个也可以了。) T- U- E6 R6 S, y
#if UserSystemClock > 6      
, t; v! ]3 S' d  nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop();    A" t# X/ o+ t
#endif
2 L9 u; n% w2 e" e# {8 y- x  if(KEYStatus == KEYStatus_Pro) KEY_PortPro();        //有按键按下,等待按键松开或按键长按认定2 N) f8 o( q3 k9 L" E- Q) Z% J
  else if(KEYStatus == KEYStatus_Ok) KEY_PortOk();   //确认按键按下: O4 [. E# u! |" H+ g# ^+ f
  else KEY_PortScan();                                                 //扫描有没有按键按下,  这一个放在最后,用 else,也是为了让程序具有自动修复能力
! X" m$ M/ s  I! O" ~, M  KEY_Output();              //置I/O为输出端口,用于显示功能! V8 H( i  g# P- S) C0 m
}3 K8 E5 s; a8 V9 C* e

0 I8 b! r% J4 B- T- bvoid KEY_Varible_Init(void)     //初始化按键相关变量的初始值.
& [( I  L* [) m+ x1 |8 j9 ~( S{
7 c% T- \3 e) {3 T3 F% X  KEYStatus = KEYStatus_Scan;
0 ]0 w5 M$ O- L" T( q' z  KEY_Value = KEYVal_NO;
( A7 ]& v" B  u7 L/ K0 C4 ~' F3 T6 i  KEY_Temp1 = 0xff;- K5 J& q+ |) {: S3 ]  H" P: p
  KEY_Temp2 = 0xff;# [1 m" y: k$ L  n! i* \" b( F1 }2 y
  KEY_Flag = L_FASE;0 G0 Z  A5 I9 d4 N; R+ ?- X
}' w; p0 v% Z' V7 C! M- m+ n, P1 z
5 q( S) ~/ P5 f! R4 x1 {. {, |. c
/ ]7 z$ a: p+ E# m- m
上面的介绍只是代码部分,硬件部分有个地方大家要注意,就是那个按键公共端上面接了一个电阻R10。它取值很重要,为了防止在按键按下时,数码管对应的段不亮。综合下面的两点,我的板子上R10实际取的是2K;3 A- F' B9 `/ ^( k1 u
1 i% x2 _" |! H: m( u0 _
1  参考STM8SR207RB数据手册,STM8认定0.3VDD为低电平,保守一点,最好不要超过0.15倍VDD。而按的上接电阻是33K,其实有点大了,
% y8 Z- R, i( F0 o    我实际焊板测试后,选取的是22K,因为这直接影响了前面判断按键状态的准确性,还有一点大家不要忽视了,芯片内部还有个上接电阻," ?" p5 h1 f  y* W4 s0 V: H$ e: b. e
   根据数据手册 上接电阻为30~80K.
) `  a) e, w1 J" K# y# ^* L2 数码管点亮它有一个压降(大家不要认数码管也是0.7V),大多数码管是2~3V的样了。所以数码管与单片机连接处加一个限流电阻,这个电+ ^2 ]( u3 d* F& x6 r
   阻是多少?7 Y5 i! s4 Y% f% V
      a,数码管点亮2ma足够了。(5 - 3)/ 2 = 1K  ,尽可能的减小这个电流,单片机驱动能力是有限的
/ n4 l+ \& m$ a* U: j/ S& K      b , I/O输出的5V分在限流电阻和R10上,保证R10的电压大于3V。' a2 h& {* O! n
/ B: a0 e: Y) j$ o( E) `- _  R
. U7 n8 C6 P; ~8 \. E

/ O- ]6 T6 S2 Y

端口电气特性

端口电气特性
w453509596 回答时间:2015-1-8 21:14:41
本帖最后由 w453509596 于 2015-1-8 21:09 编辑
# |0 @0 ?: j# i+ M! O
4 F& D5 E( m, q& d4 k     我的板子是我自己做的,上面有一个四位共阴数码管,8个LED和8个按键,一个蜂鸣器,一组测12根排线通断的接线口,一组用RS485芯片引出来的串口。我的板子的原理图和PCB我会在附件中提供。想要学习好STM8S单片机,大家也最好能有一块开发板,淘宝上卖的很便宜,少吃点香蕉就可以买到了,卖家还提供有很多的例程,个人建议大家买个简单的板子,有条件的话,建议自己做一个。
# v! U& R+ l* C# ~) q* C    目前STM8S的编程软件有 IAR FOR STM8  和官方的STVD ,个人强列推荐IAR FOR STM8,STVD比较难用,我两者都用过,现在一直在用 IAR FOR STM8 1.3(这个软件大家自己网上搜了,比超市里的香蕉还要多)。+ `- o2 ?6 M, R5 }7 V8 @
   我的板子用的芯片是STM8S207RB ,对应的数据手册和参考手册在这里直接下载。(https://www.stmcu.org.cn/document/list/index/category-17 ),第一个和第二个就是(RM0016 参考手册 和 DS5839 数据手册)。数据手册是介绍该芯片里面有哪些资源、片上外设供大家使用,以及它的电气参数(相当于超市里面挂在香蕉前面的牌子)。而参考手册刚是介绍如使用编程这款芯片了(其实这款芯片毕竟是8位单片机,入门也相对比较简单,祝大家早日能像吃香蕉一样简单的用它)。我的原理图和PCB是用 altium designer 9.3画的。: G/ S! g3 _' m4 l/ |# Z
   还有个官方的STM8S /标准外围库:  https://www.stmcu.org.cn/document/li ... ew/category-504?p=2    (倒数第二个STSW-STM8069)! L/ ?/ I# `5 t
   如果你用到的芯片也是STM8S207RB的话,直接用我的附件的中的 工程模板就可以了。代码库中有帮助文挡和官方例程。* a. c! _5 P0 `6 b/ {1 A8 D% c
   最后还有个福利,标准外围库,中文函数生成器,在附件中(STM8S真是好,这也能有! ! ! 被天上的馅饼砸中了,满满的都是幸福! ! !). g8 j4 Q4 O) {  L% b
测线板PCB.png
测线板原理图.png

测线板原理图.pdf

下载

507.07 KB, 下载次数: 228

原理图

测线板PCB.rar

下载

519.81 KB, 下载次数: 174

PCB

STM8S工程模板.rar

下载

348.53 KB, 下载次数: 250

工程模板

stm8slib.rar

下载

80.76 KB, 下载次数: 186

w453509596 回答时间:2015-1-8 21:21:01
告诉大家个小秘密,想要加快STM8的学习步伐,可以观看下STM8的视频教程,别人开发板的教程。
zhous 回答时间:2015-1-8 21:35:03
测线板是干什么用的?
jcrorxp 回答时间:2015-1-8 21:48:20
zhous 发表于 2015-1-8 21:35
6 s. P# {# N' k1 k: d# k( X测线板是干什么用的?
/ T5 o/ Y0 R) g; H
同问) x; E( i# a  D0 m2 }* _/ P0 |
是不是类似网线那种, 通断显示
+ I. S# G' J; ^0 W" Y% f3 U+ s: C. l9 m/ J2 p7 H6 I( s" \8 Q
111111.jpg 22222.png
: J+ ^' y4 r( \8 I* B" h  R
6 u: P+ s9 `* }7 T1 p+ L* W4 J/ b1 Z
w453509596 回答时间:2015-1-8 21:57:07
jcrorxp 发表于 2015-1-8 21:48
1 z+ t* Q' b& n/ f7 Z, D. y/ X0 M同问6 `$ l! R9 X4 r3 h; J5 J. s* }
是不是类似网线那种, 通断显示
( |2 a) S) h. t6 s
是这样的一个功能。
w453509596 回答时间:2015-1-8 21:59:08

STM8s定时器的使用程序

本帖最后由 w453509596 于 2015-1-9 09:33 编辑
, c! m& H* m6 Y% z  j4 _
* J3 I$ p' Y) x  STM8S包含有三种定时器,高级定时器,通用定时器和基本定时器,这三种定时器在功能上是包含关系的。在这里做一段最简单的1ms的定时功能。
9 A( s1 Y$ Z7 I, o% }  static void MCU_TIM2_Init(void)  //定时器2 1ms中断初始化/ ^) S, d' ], ]
{
  D# O$ b6 W0 F( @# {, R( T  TIM2_DeInit();                                                                 //复位所有寄存器值,这一步呢可选,为了产品稳定性,最好还是选上
$ A) r( Q0 ~: F# y. \3 Q; p  TIM2_TimeBaseInit(TIM2_PRESCALER_1, 0x07d0);          //2M 内部时钟,一分频 2000% l% W& {6 d  \/ C
  TIM2_UpdateDisableConfig(DISABLE);                             //允许更新    即是在每一次定时器溢出之后,会自动更新计数器/ V1 i/ `2 v9 Z& S" X4 h* y( j% N
  TIM2_UpdateRequestConfig(TIM2_UPDATESOURCE_REGULAR);  //只允许规则请求更新,即是只允许定时器溢出更新/ I8 H4 s# h- K
  TIM2_ITConfig(TIM2_IT_UPDATE, ENABLE);                //打开定时器溢出中断$ [' n" E: \  w. |6 i3 [7 Q; d
  TIM2_Cmd(ENABLE);                                                   //启动定时器% Y2 j1 R" A: `# \4 i1 L. ]
}" r- l* Q( Q+ A' n
  d0 [" d. u- l& N2 @
通过上面的一段程序即实现1ms 的定时功能 :我的这个示例是在默认的系统时钟,2M / 1000 = 2000 ,所以模寄存器的值0x07d0。大家是别的主频的( f! R- z2 J& D* h
话,根据想要定时的周期,对应的调相关系数即可。有库函数用起来真的很简单。我再上传一个风驰大哥的教程。
% x3 q$ \" a: ?
' U/ P  O) b) b: f+ e1 c有了定时器的中断,必有中段函数,库模板已在库函数 stm8s_it.c中写好了
0 u7 X" R! ]' o$ t# R" M  p INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13)  //定时器2溢出中断$ y7 w/ V3 F& j) W& R' {
{  U7 D* ^9 G6 ?0 y
   /*  用户函数*/- B  ~4 M+ m, R+ D5 [. j
   TIM2_ClearITPendingBit(TIM2_IT_UPDATE);          //清除定时器2溢出中断
  ^. B% E  H3 ^) ?% ]& o }- Y6 S8 W* S  q

1 S. t; g- F# X( D7 F+ b9 [- m6 ?0 W. C
6 `0 }, W. A5 g; h

10-TIM1(定时).pdf

下载

428.3 KB, 下载次数: 73

TM1定时

w453509596 回答时间:2015-1-8 21:59:23

数码管驱动

本帖最后由 w453509596 于 2015-1-9 09:58 编辑 9 j1 E/ M( N5 q/ `$ d& M8 b& n
1 c/ `9 w( U3 A( Z: G
数码管驱动分为动态驱动和静态驱动。这里只讲我的动态驱动的设计方案供大家参考/ f- v9 j  F# b/ Z
我以前上学时老师教的动态驱动是这样的。# E- u8 [- ^) c) W- w# ?! m
void main(void)- N* T* U; g7 T5 s2 X+ z
{
" l+ N% D2 x( [    while(1)) |7 c  P/ J$ b9 D8 Z/ E& {
    {
7 r- N: C  I' l& @' n# k9 R( p        display_ONE();     //第一位数码管点亮; F4 z) p  `, v* @% U8 K
        delay_MS(10);     //延时个10ms
+ @+ @0 E$ `, ~+ p3 @" s( Q        display_TWO();     //第一位数码管点亮: g. w0 N& F+ s! W7 W! |, F3 B$ H. }
        delay_MS(10);
/ t' [5 z. Q' v; m        display_THR ();     //第一位数码管点亮
6 j% w! w2 v6 o% c+ _        delay_MS(10);
7 U! R, v; Q  u    }1 d2 n# P' f! s
}
) i3 f. ]; M1 x0 e  这样的写法只适用学习如何动态显示数码管,他有两个不足的地方,一个是延时函数浪费了很多处时器时间,另一个是如果这个循环中再加上别的任务,随着工程量的加大,数码管就会越来越暗,有时候甚至不亮了。那么怎么办呢,那就得要基于动态显示的原理进行改进了。在上一段中,介绍了定时器,我分享下我的方法。我是把 这段程序放在中断中。. S2 [& m0 R6 K& \6 P" z. N/ [
INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13) " |% a; }( `0 g- }8 Q( q
{& [7 e$ h& n* ?" U. v
  switch(Dispay_Index)                    4 h% E/ M8 m% y$ A" Y
  {
% X1 s, k2 N$ {+ V6 D% Y      case 0: LED4_Disable();Dispay_Index = 1;LED_Data=LED_Buff[4];LED0_Enable();break;       //LED指示灯7 U" v* K# X- W# s$ b
      case 1: LED0_Disable();Dispay_Index = 2;LED_Data=LED_Buff[0];LED1_Enable();break;       //第一位数码
4 g* V  e. U) I      case 2: LED1_Disable();Dispay_Index = 3;LED_Data=LED_Buff[1];LED2_Enable();break;       //第二位数码* }: B% z" @1 c
      case 3: LED2_Disable();Dispay_Index = 4;LED_Data=LED_Buff[2];LED3_Enable();break;       //第三位数码
' s/ w: H; h: f  o% k, B, E( c      case 4: LED3_Disable();Dispay_Index = 5;LED_Data=LED_Buff[3];LED4_Enable();break;       //第四位数码
9 r% o1 z4 G! ?3 j% F) y" E      default  : LED4_Disable();Dispay_Index = 0;KEY_Scan();break;    //扫描按键4 H5 _" ]2 f2 _1 D- ]
  }
% x7 |+ B  e/ N8 ?  a6 i}9 M, V1 V* R1 p% i
我的这段程序是这样的一个功能,每次进中断,更换显示一位数码管。在中断中可使数码管的显示与工程的主任务独立起来。不管其它地方如何变化,, Z; A" ?5 p' ?4 s
数码管的显示总会是稳定的。Dispay_Index 它是一个全局变量。如果临时变量的话,在退出中断时它的值就消失了。最后default建议大家一定要使6 @' F2 p3 X' }, ~$ a! |2 g
用,因为它使得这个显示程序具有程序跑飞时的自我修正能力。由于我的LED和数码管是共用段码口的。所以我把LED就当作一位数码管来看待了。2 ?5 R5 G  `) Y# ]4 q. p
我的按键也是共用端口的,所以我也是把它当作一位数码管来看待的,只不过数码管是输出,它是输入而已。下一段我和大家分享一下我的按键驱动6 {/ b- e! G4 S5 e) ]. k0 K7 a3 W
方法
3 t+ y+ `" I+ `  l  
+ d* O; p: l# N: ~, @4 x( ]  0 S3 U( x- w: p

+ x& u+ ?2 }. y7 t! d* i# ~( c9 [9 E2 s  H+ k
0 d% y6 A; J7 t# Y# h
w453509596 回答时间:2015-1-8 21:59:54

这一节介绍下如何基于库函数的头文件让STM8S支持位操作

本帖最后由 w453509596 于 2015-1-9 11:57 编辑 ( h: |' B$ o, \( V; b, I) W
3 s  _; R% Y6 H2 w5 o* Z- @+ Z* Z
    在使用51单片机中,我们可以很方便的定义位  sbit  LED_0 = P0^1;
3 E3 e4 V" M: `   但STM8S库和IAR并不支持这样的操作,这给我们在写应用代码时带来了很多不便。那我们只能对面STM8S的I/O寄存器进行重新封装了。, s9 X6 M* V2 u, r, m( X( O$ b
   在正式写程序时,我们要了解结构体在内存分配时,内存是连续不断的一片。 结构体和联合体部分不太理解的同学大家网找找。! G7 {. s& a2 D& m4 L5 r9 G& R- ~
   先看库是如何封装I/O寄存器的。
+ h& {1 O2 _2 {2 w* Q, _   typedef struct GPIO_struct     //定义I/O结构体类型
& R* W, v; T2 G. d0 ` {# z" ?1 `" @( m& k" E3 ?
  __IO uint8_t ODR; //!< Output Data Register ' Q1 m& a4 L7 _1 p, ]% u+ J, u" X
  __IO uint8_t IDR; //!< Input Data Register
5 h; n" d! S' A# p1 }. X  __IO uint8_t DDR; //!< Data Direction Register
! {$ z  |* r! h8 _/ I) e  __IO uint8_t CR1; //!< Configuration Register 1
" R$ ?( ^& b; T2 S+ L  __IO uint8_t CR2; //!< Configuration Register 2
$ ?5 X- G$ P* v6 C3 A }) j/ M" n' s6 d" O- v; J
GPIO_TypeDef;  
: L  R# ~) V# k+ t/ V$ K  F7 u" r+ v+ @) i* A( V
#define GPIOA ((GPIO_TypeDef *) GPIOA_BaseAddress)   //强制定义端口名
  d0 `$ M' S1 _2 v3 @3 q$ v) U: T1 ^9 o2 v
      这样的话,我们想往 GPIOA上送数据,只要这样即可: / s; g: J; n7 R  l  c4 z7 M7 n# m
      GPIO->ODR = 0x01;        //即可轻松的为 GPIOA端口赋值了
! x6 F9 L* E* @3 R8 I0 L; Z
, O$ O4 _5 O- l% e/ D2 E& `3 x我们要如何封装呢。这是我现在用的。6 r% _2 @2 S% C: I9 Z/ A, k
typedef struct GPIOBIT_struct    //重新定义端口  因为一般只要用到数据输入和输出即可,我只定义了 ODR 和 IDR
: i8 f) ?8 v, r! X{- C+ o- c4 i9 I+ \& m
union
- s6 Y! @1 |# ]! _. Y% V7 r0 x {
1 e/ V6 R2 t$ G: N1 F% ?3 L" }1 Q   __IO uint8_t    All;% ~/ e8 {) a' r8 s. @" y
   struct; t( N4 a4 g% B1 d: ?5 t( w
   {
  F8 m1 f% ?& [8 N   __IO uint8_t B0:1;
" H  S% `2 G; ?6 t: y   __IO uint8_t B1:1;
) j! R* s0 Y  Z5 }$ F   __IO uint8_t B2:1;1 S7 r, Q3 E9 Y0 O0 v& ~) t) R: O& Q
   __IO uint8_t B3:1;
, Z6 W/ d; A6 X; h' w   __IO uint8_t B4:1;
1 b9 v1 w& I7 x, }& S* P   __IO uint8_t B5:1;/ q/ ^: Z- E6 K
   __IO uint8_t B6:1;1 M7 J/ U6 z/ f! ]; [3 x
   __IO uint8_t B7:1;
9 u' n+ B: e/ a! A4 f9 v" }  }Bits;7 q5 Y, l4 q0 H5 W8 i. {
}ODR,IDR;3 z3 J) l" P* j* G; L, P
}GPIOBIT_TypeDef;
) l2 I, |7 B* J' w) ]5 O4 [+ i( O3 V; v) q" |# N' I! U- ]
#define GPIOANEW (*((GPIOBIT_TypeDef *) GPIOA_BaseAddress))
; |6 ?" F* Z6 o6 a) h2 k' v" R) D0 F0 K+ m
    这样将GPIOA重新命名为 GPIOANEW  现在往GPIOA口输出数据就可以样写了
. s7 b/ b$ ~) k: B0 J  v    GPIOANEW->ODR.All = 0x01;
& x' K: p' ^) H$ O' ^( w/ x1 |8 w    单独往第1位写如何写呢? 如下即可。
( C3 b" F# t" O+ }, ]: L6 Z   GPIOANEW->ODR.Bits.B0 = 1  ) d$ D# R# o, _9 p# f' K7 m# P2 h
5 `9 F1 e7 A2 Q: J8 x# \) N
   这样写是不是太麻烦呢,我们再封装它
7 {4 @2 a/ T3 A& J- k# `! A5 [   #define  GPIOA_0  GPIOANEW->ODR.Bits.B1& {2 |. G  `# X/ k* I7 |
    GPIOA_0 = 1;0 l8 [% w* }( f+ b' U8 s
' V) A, C6 R# u2 i
关于它的位操作这么多也差不多够用了,其它大家自己多思考了
/ T9 m5 c# s; [. g5 m2 v
2 t1 A) K/ V0 |: i6 f) Y& d5 b  
5 M' l* N  l# z
+ S( ^6 K8 Z, d0 R$ \. p* x# X$ L; \& z
' }+ ~+ t: X0 g. D% o
w453509596 回答时间:2015-1-8 22:00:11

接下来就是介绍如何进行测线了。

本帖最后由 w453509596 于 2015-1-9 12:47 编辑
; `0 m3 v. S8 D, h3 u9 `/ S
  u* s' `5 q% `. J& {在测线程序设计之前,还是老样子,先想好这个用什么方法去测。; S; ~3 j7 v0 f1 H$ E3 D! J
在大批量生产排线的时候,一般会出现如下三种问题" G5 J! P. k& `7 L: z, P
1.  线断了     2. 线交叉了     3.可能存在接触不良的情况
3 g3 A1 _. Z8 }* j3 ^; F* G$ T- M" P( K如果用人眼去识别哪些线不好,哪些是好的。几根好办,几千条线呢,几万条怎么办呢。  只能借助自动化设备了。
0 p3 B! z; y, u  I/ |* Y; {& Q9 `/ G- }/ y, b
我呢提供一个我的思路。我还是放在中断当中去做。# ]( {& G  S' R* q
第1次进中断,我给第1根线送一个低电平,再在线的另一端去检测它,将这个值保存在变量的第1位中,再将第1个端口复位为高电平/ c$ V$ ]4 |" D4 M
第2次进中断,我给第2根线送一个低电平,再在线的另一端去检测它,将这个值保存在变量的第2位中,再将第2个端口复位为高电平
5 a, d( z% O+ q! n3 `% K...7 s* H3 o! B1 E
...2 @, y$ G1 N: @* \* Q% F% T% p7 A
第12次进中断,我给第12根线送一个低电平,再在线的另一端去检测它,将这个值保存在变量的第12位中,再将第12个端口复位为高电平0 {  U0 Q# x( j% W1 Y
测完了12根线后。我判断这12根的状态,并保留下来。作一次测线计数。
; x( F- V7 `- z; I9 Z) Q  j' q我们知道是线插上插座和拔下插座的过程中,这个状态是不稳定的。为了避免这个情况的误判, 我每次在测完12根线的循环之后,都记下它的
/ M+ W' u9 X2 F7 M# a* M状态,直到10次连续测量的状态都是一样的,才最终认定这根线是好还是不好。! l/ ^0 g" P1 x7 o7 ]
1.  对于好的线,在数码管上面显示一个 PASS  表示通过
# e& a* @0 l- J; d- ?, d2.  那么对于不好的呢,找出是哪一根线不好,并把它在数码管上显示出来,让检测人员贴上标签,便于产线上工作人员维修# D4 f7 q( ?6 a$ q0 ?3 D1 z( P
     如何算快速算这个线是哪一根呢?方法有很多种,
6 @0 U" |& x: I0 `. j( T, z+ ~/ A& [     我用的是杳表法。把UCOSII当中 找最高优先级的表给复制过来就可以了。9 ?8 X# X3 O( H$ F- {& b$ M

" o2 w7 W6 b# J2 h: H# a是不是这样就算完了呢,为了使我们做出来的东西更像一个产品,我们还要给它润色。% }( J3 d7 t% }/ X+ s
  1. 我还会让产品计下测量多少个排线,产品的合格率是多少?
3 D; _6 q" O) S8 ?( c  E1 v  2. 将最近10次的产品测量数据进行对比,看看产品的生产效率和合格的率情况,  便于提高生产 (STM8S有内部EEPROM,这些数必须保存在其中)
/ b1 i2 C3 X4 _  B0 p# W) i  3. 根据其它产品的需要,我测的线肯定能只是12根的。 只要不超过12根,我们可以通过这个菜单去设定的
; F- Z, r+ H+ n  4. 可以通串口将这些数据上传到电脑上,结合上位机软件,将它们制表格% Z5 E5 E4 Y4 w6 Y: n2 S

% t! w9 b7 Y! O) q) {* h$ U
3 k1 I7 L0 B9 S+ [* X( ]. T如何去写这个菜单的结构,其实也有很多东西,大家可以在别处杳查。在8位机写一个很大的菜单,而且要有高的处理速度,我用是的结构体去做的,5 w! ^( t/ ?3 y4 l/ ?6 r6 _+ z) Z
也是在网上的一位大哥的贴子上学的,可如今找不到连接了,它可以让一个10 x10 的菜单执行速度 和 1X 1速度一样快。
7 ]) y- H" x" p, P
. P5 m3 L3 m9 _0 S" @$ h, b这个测线板本来是想写成教大家入门STM8S的,我不常写这一类文档。由于工作上比较忙,写着写着就变了。我更多的是写出了我平常工作中总结/ c3 d8 o! U6 t2 t  D
出来的比较好的程序设计思想。我把我的程序也上传过上来。) b( N1 z4 E, A
+ G7 r! g, h  N+ J  V. T* g  y& H
个人写文档能力差,希望能有写文档能力强的朋友指导指导。俗话说: 会写画板子,会写程序的叫技术员; 会写报告、会做计划的是经理;  会做策划,会做方案的是老板。. Y' H: [' O# U

  O$ h+ }* g; b3 \/ _祝我们这些一心想学想做技术的朋友们早是成为老板!!!!
! M0 \+ q: H; O! B' q. l  D- Y7 k! T9 c; ^6 X! O3 g

! ]4 ?9 t, x5 O. N% T
! T  F8 m7 V$ N8 C0 _: ^
) q, s* x8 u( x3 [- z

测线板程序.rar

下载

413.18 KB, 下载次数: 55

测线板程序

aderson 回答时间:2015-1-8 22:08:02
那玩意儿就十块多钱一个有必要么。) s4 n  w/ {! U$ Y
w453509596 回答时间:2015-1-9 13:00:31

基于UCOSII 的测线板程序

本帖最后由 w453509596 于 2015-1-9 13:07 编辑
7 T) L' r; e3 n/ D$ Q
' y9 F$ g  s0 X6 P1 S如果家能看我的贴子做出了这个测线板,那么STM8S的应用也就没有什么问题了。我在上传一基于UCOSII2.5的测线板的程序,让大家学一学UCOSII 的使用 和如何把UCOSII 移植到STM8S上面,移植我参考的也是风驰大哥的教程,他移植的UCOSII 2.9 ,我自己在学完教程后移植的是UCOSII 2.52版的。我讲一点个人对写程序感想吧。写程序最重要的程序的结构,写程序的代码风格。其实学会用一个单片机并不难,像STM8S买一块开发板,对着入门教程很快就会了,我入门大概花了两周的时间吧。(这里我真心感谢风驰大哥,他把他的教程免费共享出来,在我心中他和STM32的原子哥都非常值得我们去尊敬,他们把他们的东西免费共享给了很多利益不相干的人,包括他们的竟争对手,这不是一般人能做到的)

基于UCOSII的测线板.rar

下载

478.04 KB, 下载次数: 42

w453509596 回答时间:2015-1-9 13:11:55

关于STM8S看门狗

本帖最后由 w453509596 于 2015-1-9 13:14 编辑 0 s. a2 @/ M8 V0 j
% f# D  E: v; @0 b
关于STM8S的看门狗,有一点非常要注意,它这个和我正常写看门狗不太一样。它要先开启看门狗,然后才能对看门狗进行配置,这一点官方的参考手册上标的不太明确
5 ]1 }3 A+ x; q) I0 G) HSTM8S的看门狗应该是这样的顺序, H+ P+ X: t. q5 ~/ X5 A
8 I$ a' _8 Q  K& @$ D
static void MCU_IWOG_Init(void)   //看门狗初始化,只允许写一次. M) ]4 V2 B8 _' S: r
{
9 u7 h5 T3 I4 }; D  IWDG_Enable();                                //开看门狗* {) ]8 y' a& I( W
  IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //写允许
2 ~& r$ U+ v) Q6 Y: v5 t) i  IWDG_SetPrescaler(IWDG_Prescaler_256);        //256分频7 t3 e3 h6 `* G+ Q1 X0 Z
  IWDG_SetReload(0xfe);                         //254的重载值
" G/ F5 r# @2 D1 |- l  IWDG_ReloadCounter();                         //刷新计数
! |) C6 Z# n* `- W, r}
123下一页

所属标签

相似技术帖

关于
我们是谁
投资者关系
意法半导体可持续发展举措
创新与技术
意法半导体官网
联系我们
联系ST分支机构
寻找销售人员和分销渠道
社区
媒体中心
活动与培训
隐私策略
隐私策略
Cookies管理
行使您的权利
官方最新发布
人形机器人运动控制、感知与智能配电
半导体创新技术与应用方向
EE架构与软件定义汽车
12V/48V 汽车智能配电(SPD)
区域控制单元(ZCU)与分区架构
关注我们
st-img 微信公众号
st-img 手机版