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

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

[复制链接]
w453509596 发布时间:2015-1-8 21:14
本帖最后由 w453509596 于 2015-1-9 13:01 编辑
5 f* c, k" x$ K3 o2 n. G' d2 O+ S! C/ Z  I
    我刚刚使用STM8S几个月,从刚开始到现在会使用,在这过程中也走了很多的弯路,浪费了许多时间。我看到也有一些刚接触STM8的同学和我刚开始一样,对于入门STM8无从下手。我在这里把我入门的过程给分享出来,希望能对想入门STM8S的同学有所帮助。根据我个人的学习经历,感觉初学者最需要的是从一个实际的项目入手,让初学者在不熟悉其全部理论的情况下也可以把东西做出来,然后再回过头来去理解其中的全部原理。我的STM8入门是从一个测线板开始的,我把我的学习过程和其中碰到的问题全部写了来。
, g$ c6 [/ W" ]' e   1 准备工作: 一块STM8学习板,编程软件,数据手册,参考手册, 一颗坚不可崔的决心。/ f4 w5 z8 ?, ]
   想做成一个东西,兴趣、压力、动力,这几点非常重要,我希望朋友们在学习STM8之前能给自己找一个学习的理由,绝对会事办功倍,我当初给自己设了一个理由,我学会了STM8S,就能够涨工资,然后就可以找到个漂亮的女朋友。学习STM8有着他天然的优势,首先这芯片价格便宜(香蕉超市最便宜卖2块2,它最便宜的只要1块5);其次,学习它只需要用到我们最喜爱的语言(chinese Simple);再次它的官方资料非常多,官方库的程序很直观,不像飞思卡尔什么的,各种秀操作。最后还有我们这个强大的社区  (https://www.stmcu.org.cn/)。我当时的资料全部都在这个社区找的。( \2 N# m" t1 ]3 f6 o
" a+ I- m! I) d8 V3 I

* ^0 ]! r" m! Q
赞 收藏 5 评论44 发布时间:2015-1-8 21:14

举报

44个回答
w453509596 回答时间:2015-1-8 21:56:18
本帖最后由 w453509596 于 2015-1-8 22:22 编辑 & i% \  Z7 s& g/ v
! g5 w" G+ C/ ^0 s
首先编程软件的安装,开发环境的搭建,以及想自己建立工程模板的同学们,请参考附件。我在这里介绍如何驱动我的板子上面的LED。
3 `; w6 D- }! |% ^  从原理图上可以看出,我的8颗LED连接PG0~PG7上面,公共端连接在ULN2003A上,由PE0端口驱动。如果我想要第 1 个小灯点亮,只要 PG = 0x01 , PE0 = 1 即可。
. p, `' a2 j, A- C% C' R  如查想做个LED的闪烁效果,大家可以在MAIN文件中加上如下一段简单的程序
+ R2 O& T: M3 t. g# f1 |' [2 s# ]' j
7 T5 A) L9 w9 ~8 Kvoid delay(unsigned int t)   " v  K1 p6 ?# [! p2 u! d
{% `* Z) {/ m* Y7 m6 C' N( O
  unsigned char i;1 _# }% l" {# B) [/ B  ]8 e
  while(t--)- t7 l) K$ i8 f& g
  {; c/ p! S' N7 z
    for(i=0;i<250;i++);
4 |6 T# O6 D7 q" `0 P2 L  }
4 I1 S4 ^7 U' ]2 z+ I}1 A; N* ]( a# p: p4 L
1 x8 q7 |, Z. X$ I' N+ _. _7 z
void main(void)
/ b/ p# M% L" x. w( X& R3 [! T8 s6 y{
5 p* M. X/ x9 Z' v& W6 ]* n* V   GPIO_DeInit(GPIOG);  //复位G端口寄存器
1 c: ]$ `" t6 Z7 i/ X* q; J7 Z   GPIO_DeInit(GPIOE);  //复位E端口寄存器
6 V  d& W$ l3 D* R6 w! Z3 a- J   # d/ L! o: e. w, E* E
   GPIO_Init(GPIOG,GPIO_PIN_ALL,GPIO_MODE_OUT_PP_LOW_SLOW); //初始化GPIOG为推挽 低速 输出
. q7 V2 m/ b) c6 O8 A3 e                                                                                                                //初始电平为低电平
2 `) V5 P/ T) m3 |   GPIO_Init(GPIOE,GPIO_PIN_0,GPIO_MODE_OUT_PP_LOW_SLOW);   //初始化GPIOE0为推挽 低速 输出
9 A/ |7 x* x  S( v' h7 t. ?. z                                                                                                               //初始电平为低电平
' W# Y& b! F+ {& b- L   ' b! b. \" M' Z; o& d: C" J! c
   GPIO_WriteHigh(GPIOE, GPIO_PIN_0);   //打开LED的公共端  即 PE0 = 18 G! f$ K+ B$ d6 O/ o
  /* Infinite loop */# |9 g! f2 m. l2 n/ T
  while (1)+ l( `' ]# C; z6 d. ]
  {* X% j7 v  W: b' A) l; W6 x; V
    GPIO_WriteHigh(GPIOG, GPIO_PIN_0);   //点亮第1个LED   即PG0 = 1
6 s0 f4 m: Z/ u* C) R% B) \    delay(1000);                                          //延时一小段时间  B9 D% N5 d& O& L  }
    GPIO_WriteLow(GPIOG, GPIO_PIN_0);   //关闭每1个LED   即PG0 = 0
7 J+ s$ g# K$ C$ L: W, j& y2 m    delay(1000);                                          //延时一小段时间
) j7 e) r" a2 Y+ t; `  }* y) j! S- \4 A9 B4 N! k
}; ]# T* f6 _# G8 Y  F' s  A
& V; \! H" r' v5 \
在这段程序中,单片机使用的是上电复位后默认的初始化(内部16M的参考时钟8分频,即2MHz作为系统主频)。
: x& ]; x+ @* ^
# z% H" ]' y' C; J1 |GPIO_Init(GPIOG,GPIO_PIN_ALL,GPIO_MODE_OUT_PP_LOW_SLOW);函数的原型如下
" b' B/ y; j, R9 I' ~  x" D7 ], Cvoid GPIO_Init(GPIO_TypeDef* GPIOx, GPIO_Pin_TypeDef GPIO_Pin, GPIO_Mode_TypeDef GPIO_Mode)# u3 F0 u- @, u
它的功能是初始化一个端口的指定引脚为某种状态) R/ ~2 b- X8 L( n& e5 j7 i

# s: K' e7 ?3 V+ S" C这个函数它有三个参数, : ]) X* c. ~; f; v4 R
第一个 GPIO_TypeDef*   GPIOx    ( 选择端口)
  r& l/ j1 C. _* M& `! Z% ~其中这个 GPIOx   可以替换成 GPIOA 、 GPIOB、 GIPOC、GPIOD、GPIOE、GPIOF
, o+ @0 y9 S/ D5 m* \) k( _8 a' x- ?! x2 e  _
第二个参数是  GPIO_Pin_TypeDef   GPIO_Pin      (选择引脚)  # [$ [5 A# l2 m, M  s  p- g# B/ y
其中这个 GPIO_Pin 可以替换成下面这些
; F$ t5 B# I; i  GPIO_PIN_0    = ((uint8_t)0x01),  /*!< Pin 0 selected */
+ G. b! _$ Q1 u3 ?0 p0 `' d# D  GPIO_PIN_1    = ((uint8_t)0x02),  /*!< Pin 1 selected */  g8 j( Y; u, I  n' A! v2 |- X
  GPIO_PIN_2    = ((uint8_t)0x04),  /*!< Pin 2 selected */+ k. t5 ^' [- G  R( y* B1 q# z; U
  GPIO_PIN_3    = ((uint8_t)0x08),   /*!< Pin 3 selected */! }2 U0 g! P7 f. K6 s. h
  GPIO_PIN_4    = ((uint8_t)0x10),  /*!< Pin 4 selected */4 R4 {0 R- `9 t2 q9 [# [; A. U
  GPIO_PIN_5    = ((uint8_t)0x20),  /*!< Pin 5 selected */. i! ~. K, U6 b3 o
  GPIO_PIN_6    = ((uint8_t)0x40),  /*!< Pin 6 selected */
: u/ @& a( T4 ?  GPIO_PIN_7    = ((uint8_t)0x80),  /*!< Pin 7 selected */
1 M) d) Y& S: a" }# c7 p  GPIO_PIN_LNIB = ((uint8_t)0x0F),  /*!< Low nibble pins selected */
; E9 k* _, g* |; ^6 p  GPIO_PIN_HNIB = ((uint8_t)0xF0),  /*!< High nibble pins selected */
4 e: n- K1 k4 E- k6 i' Z5 O+ ^% a  GPIO_PIN_ALL  = ((uint8_t)0xFF)   /*!< All pins selected */
% W+ o9 Z& R4 |' Y' T  z+ n6 D
' X8 n, D: \( |6 f6 f% P第三个参数是  GPIO_Mode_TypeDef   GPIO_Mode  (选择模式); y5 {1 J- o5 a  `& I7 H" q
其中这个 GPIO_Mode 可以替换成下面这些
1 L) b$ J6 L  C5 t4 M; tGPIO_MODE_IN_FL_NO_IT      = (uint8_t)0x00,  /*!< Input floating, no external interrupt */8 j8 {: [. Z0 K# S' w, j
  GPIO_MODE_IN_PU_NO_IT      = (uint8_t)0x40,  /*!< Input pull-up, no external interrupt */  I# L2 A' Y3 z& g4 D( v
  GPIO_MODE_IN_FL_IT         = (uint8_t)0x20,  /*!< Input floating, external interrupt */
* X- G( Z0 ^  K$ F  GPIO_MODE_IN_PU_IT         = (uint8_t)0x60,  /*!< Input pull-up, external interrupt */
5 ^& o9 A1 P& P9 _  GPIO_MODE_OUT_OD_LOW_FAST  = (uint8_t)0xA0,  /*!< Output open-drain, low level, 10MHz */& u1 H( m( \0 H3 T7 I  e6 T, K
  GPIO_MODE_OUT_PP_LOW_FAST  = (uint8_t)0xE0,  /*!< Output push-pull, low level, 10MHz */6 H+ ~; I& Z  c. F9 F
  GPIO_MODE_OUT_OD_LOW_SLOW  = (uint8_t)0x80,  /*!< Output open-drain, low level, 2MHz */8 }* v# Y$ X$ D7 B0 d% F
  GPIO_MODE_OUT_PP_LOW_SLOW  = (uint8_t)0xC0,  /*!< Output push-pull, low level, 2MHz */
4 N7 V1 G8 A- A% b) d  GPIO_MODE_OUT_OD_HIZ_FAST  = (uint8_t)0xB0,  /*!< Output open-drain, high-impedance level,10MHz */
3 v( S% W( X9 H  ?1 q: S' F  k  GPIO_MODE_OUT_PP_HIGH_FAST = (uint8_t)0xF0,  /*!< Output push-pull, high level, 10MHz */+ m- I4 m* o+ l, l& \9 Z. y
  GPIO_MODE_OUT_OD_HIZ_SLOW  = (uint8_t)0x90,  /*!< Output open-drain, high-impedance level, 2MHz */
3 L4 e7 Z$ r  p  GPIO_MODE_OUT_PP_HIGH_SLOW = (uint8_t)0xD0   /*!< Output push-pull, high level, 2MHz
  i& z5 e. ^0 z; t3 v
; ~6 f+ K  @1 f) {( d. O* J. Z* m! k) b* Y/ L9 ?
GPIO_TypeDef 是一个结构体类型 ,它的定义如下: (这个对于初学单片机的同学可以不用关心)
$ C- M& A$ G% U% k2 R  F8 Z+ [typedef struct GPIO_struct! o) E4 [6 I7 E
{
7 |* F1 s! G6 @/ q- M8 }. ^  __IO uint8_t ODR; // 数据输出寄存器( I; d' g3 w) {9 k
  __IO uint8_t IDR; //数据输入寄存器$ q3 A5 Q0 S" e
  __IO uint8_t DDR; //端口方向寄存器  . z/ F9 K! M4 p+ _; ~0 T& t( ?1 C
  __IO uint8_t CR1; //控制寄存器1
) S2 ^1 C$ E  k- d  __IO uint8_t CR2; //控制寄存器22 L) w/ f$ u, v7 {  Z
}
1 G  C: p; K2 EGPIO_TypeDef;
1 y$ d$ I3 C2 |. l. e2 G/ X9 X+ P0 L5 }
#define GPIOA ((GPIO_TypeDef *) GPIOA_BaseAddress)   //这里是为从 GPIOA_BaseAddress 到  GPIOA_BaseAddress + 5 这段地址                                                                                                 //取个名字叫GPIOA  ,STM8所的寄存器都是差不多这样定义的
& g) Y  k6 L) \  G* m#define GPIOB ((GPIO_TypeDef *) GPIOB_BaseAddress). R; E$ }# Y8 x' ]) a
#define GPIOC ((GPIO_TypeDef *) GPIOC_BaseAddress)9 ]) U; i) i: l2 G# J- {
#define GPIOD ((GPIO_TypeDef *) GPIOD_BaseAddress)
5 C$ `# [8 W, `8 Q8 J' ~( v#define GPIOE ((GPIO_TypeDef *) GPIOE_BaseAddress)
* Y9 b2 S4 O- d1 `3 P( \# t8 ^#define GPIOF ((GPIO_TypeDef *) GPIOF_BaseAddress)4 }2 W7 b# }) T* w2 [" S
" N6 [! \" o7 A" S  E! n1 C  g
9 p/ x7 m$ |# i/ m' d
) @. o# d1 D" }% W6 u6 H

' c; M' B% {0 q0 P% T( ?" p1 t0 c0 M3 W' ^1 [
1 w- Q1 D) z# U# N' q

. c3 B& Q1 N2 a5 n. V; S/ b9 L) a8 H6 Y4 T0 z
0 u& W: [, V  Q; P+ a( l5 R; R& z
# v) G8 w" K) c
& X) J* L' l4 T

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 编辑
# J" O, z# v! K+ n, [- a. {
8 n( p0 G! x/ G; L基于STM8S的红外遥控功能。我给大家分享一段代码。由于是产品了,不上传全部程序了* D; _3 Z& W0 {$ ]
FuncState InfraredWate_Flag;  //等待按键松开标志8 w; k- W: ]4 v6 n. n0 m; Q
Uint8 InfraredWate_Index;     //用于等待按键松开计时0 W4 g' w( X5 o
FuncState InfraredRec_Flag;   //红外采集完成标志" e. H3 J$ v/ u" H" H; l8 g
Uint8 InfraredCode;           //红外接收代码
# e, C1 y9 j1 IUint8 InfraredCode_Index;     //红外接位计数( a9 q# m% S$ Y% |3 ?1 u
Uint8 InfraredBuffer_H;       //红外识别码接收缓存) d) K% p) }/ h# o. I8 w
Uint8 InfraredBuffer_L;       //红外接收代码缓存" L* b! @* T0 i( C6 V8 w& c3 w" R6 Q
Uint8 InfPeriod_Status;       //红外周期状态
- r1 F# x0 S6 j; |$ EUint16 TimeCounterVal;        //计数器临时值& o7 W1 Q# E1 J' R. D
Uint8 ReciveIndex;            //红外接收计数
( w- o! a  C* M. M5 _$ X  }$ {4 k! _+ p& [3 X  k& x9 m3 f2 e
static void TimeCounter_Start(void)    //启动计数" `$ @6 r& M7 z" f8 l
{3 K: g) {6 k, T' v, y  u
    TIM2->CNTRH = 0;) j8 D% W$ s4 _( T& d. N
    TIM2->CNTRL = 1;& b5 f: I5 U3 J! G/ m! t3 ]
    TIM2->CR1 |= 0x01;# B0 _6 x% t7 G- }8 u
}, c, u- ^( Q: r5 F6 h

  ~* g, ~8 L& t) hvoid TimeCounter_Stop(void)    //停止计数
0 o: m% ^: k4 G2 E5 B8 s0 i{
# X) J2 j' Z5 |& Y    TIM2->CR1 &= 0xfe;9 w+ e$ x6 y+ H/ _3 @: V
}) U. c5 z1 a& O2 ~( q5 P
; [2 n; Z& @7 L# y9 [) A
static void InfraredRec_Bit(Uint8* BufferAddr)  g4 _/ C/ e# E. z- ]% v
{2 e  h8 p9 K5 s1 S5 A  e  x
   if((12000 < TimeCounterVal)&&(TimeCounterVal < 22000))    //0周期约为17000
$ n) ]! t. @3 C& ?9 n   {6 L* ?1 S. k1 c( ]8 b- c
     *BufferAddr = (*BufferAddr) * 2;
) b7 _& K' a% _   }
7 x) F( {. \" {- W& o3 r   else if((30000 < TimeCounterVal)&&(TimeCounterVal < 40000))  //1周期约为35000
/ S' D# Q$ U7 @; C/ q& e% `; J9 d  s   {
  [6 u9 [( ?: x- d: @6 c* @     *BufferAddr = ((*BufferAddr) * 2) + 1;
* P& F! _& k- E- v   }
* P3 y1 I( \& I: i/ W0 ~   else ReciveIndex = 0;
( q+ O# i) u6 C+ m0 E% {}
4 U% K% M8 p% o- g+ a/ \% P
* m2 H# T* m& k- Vvoid InfraredInterrupt_Process(void)
1 D" \$ f% x1 c5 |6 f1 b{2 n7 u/ q4 t8 a/ _6 Y. k+ f
  if(InfraredWate_Flag != L_FASE)       //等待接收到按键松开的间隔符,才开始下次接收  每次中断4ms,10次约40ms2 d# K2 V. }/ }
  {8 ^$ A* d9 s1 g% H! N+ p
    if(InfraredWate_Index <10) InfraredWate_Index ++;  
( n+ ^+ V/ I3 m$ L    else
! I* a1 @8 y/ I$ |& E8 C    {  E! E! S6 i# P! A8 f/ z4 [
      InfraredWate_Flag = L_FASE;                                   //已等到间隔符,清标志位      
/ [# [: S" q! x7 e6 p6 Q0 C: z5 X& C* e      TimeCounter_Stop();  
( k( |( _7 x2 X      InfPeriod_Status = InfPeriod_Start;( h" E. m) s& ~4 s4 q
    }
8 O. y( P0 D) [/ m' F1 ?  }
1 H" A: H  @6 g' T7 o1 [0 |/ E  else                            //防止计数中间产生的,错把间隔符当成正常位。还有一种是由于排除红外不工作时产生的干扰。1 D, l: R7 s  V1 @5 I
  {4 y. U+ o, F' W6 s4 n1 ?  j
    TimeCounter_Stop();. K9 u, Y' U3 }0 t  H: F# ^
    InfPeriod_Status = InfPeriod_Start;5 b' `! z/ V  }! C( Z2 [3 q% [/ A
  }, N: [! D/ @1 S
}% J$ f; V( Y* L' \7 s

" w+ S' c* S$ k' o, T6 L' zvoid PeripheralInfrared_Receive(void)2 C2 N9 x5 P# r5 h8 h! [) P& T
{
3 H% h5 N# `; c4 f# N/ b9 T  if(InfraredWate_Flag == L_FASE)                            //处于非等待间隔符状态,开始正常接收  " L7 E# g" a9 F% v
  {. J/ w& v- U  N
    if(InfPeriod_Status == InfPeriod_Stop)                   //开始接收数据
5 H8 `. y( n. ^  W& b' q    {
1 i& J1 G3 b8 _. m      disableInterrupts();, p1 A  n: m# P; `+ @7 d1 E
      TimeCounterVal  = ((uint16_t)TIM2->CNTRH << 8);
% p) h8 |: w0 T, i      TimeCounterVal |= (uint16_t)(TIM2->CNTRL);
- K+ I$ _- U( f; W0 g& w  c$ s- M      TimeCounter_Start();
9 j/ w$ ~1 p& ?: [6 T: w5 O      enableInterrupts();                                //存在一些硬件上的互锁机制,为了使得数据更准确,这里关掉中断,防止其它干扰% T4 y1 {% M/ c& ^- B' x
      
! G$ V. ?' F& y- D      ReciveIndex ++;
; h' _( N0 i. U4 i      if(ReciveIndex <= 8)  InfraredRec_Bit(&InfraredBuffer_H); //前8位数据+ e! v: N, M; g/ O2 `
      else  InfraredRec_Bit(&InfraredBuffer_L);                 //后8位数据                # _( M5 [, L- c/ k7 c+ q
      if(ReciveIndex >= 16)6 q! M0 o. I; ~6 [# Z- D. r) u
      {& H! _, t9 p9 V' J- b; z" H' Y
        InfPeriod_Status = InfPeriod_Start;& s& r( R! k& _3 C. e
        if(InfraredBuffer_H == InfraredUser_Code)   //如果识别码正确# h$ n1 g5 t3 c' Z% m
        {4 U. d- d2 b4 n0 @
          InfraredWate_Flag = L_TRUE;               //已接收到功能码,等待间隔符
) Z' T  x: [+ X# b6 y2 [          InfraredWate_Index = 0;
. \3 N6 k9 Z" H0 ]/ v          InfraredRec_Flag = L_TRUE;               //5 j, n, x" P+ a5 F/ S
          InfraredCode = InfraredBuffer_L;         // 将数据送入缓存区  
4 T4 u# e# [2 S# O6 c        }
* u7 J( L* ?' Z* C      } ! N4 m: v; e% k8 Z! K' V$ V
    }
! {' g! J- X, Q    else                                      //如果接收到了启始符,置标志位,开始接收数据
- k, P& S) m; U( G    {& |3 H# z% G3 |9 I) n' L; |
      TimeCounter_Start();4 e" O( o- u' w7 }
      InfPeriod_Status = InfPeriod_Stop;
9 R+ l' Z1 \1 V" x1 A. Q: F      ReciveIndex = 0;
  {+ n3 H0 D* f5 T    }' p8 R. X5 ~" A- [% z
: p3 M9 B# d( r1 t7 H0 c
  }
+ J# l" E6 o- d: g  else InfraredWate_Index = 0;                //在等待按键松开,理论上讲,是不允许再接收重复红外信号的
: C+ z$ i! |5 F}https://www.stmcu.org.cn/module/foru ... &pid=2049512&page=12 J$ e8 q; ?, a; q

0 t. a1 J( E( Q, B' f: wvoid Infrared_InitVar(void)
8 {9 J0 w/ e5 z  ~4 S1 l{
# E' L* v2 A6 H% N  InfPeriod_Status = InfPeriod_Start;
9 U) c; E- r3 ]8 W6 p2 d7 ?  _  TimeCounterVal = 0;
* U2 m6 b7 q* ]: g* B  ReciveIndex = 0;
  c  {9 J4 \6 A. s  InfraredBuffer_H = 0;
) v# i! a1 P2 s  InfraredBuffer_L = 0;
6 k7 W) e& [; ?  InfraredCode = 0;
; x% q6 Q* E6 K$ p  InfraredCode_Index = 0;8 k$ u6 y# q. v+ }1 \: G$ u1 N
  InfraredRec_Flag = L_FASE;
/ N) ?) P! w. N/ N  InfraredWate_Flag = L_FASE;
2 z" u) v; r$ y8 ]  InfraredWate_Index = 0;' _  C3 N2 W( B3 \; q$ C) I
}; D* H# a) G' h& l# D/ l

, B, R0 ^+ q" R8 {0 k- f: y* P( b3 c9 x1 e+ h5 ~: Q3 C& Y
在这个红外编码中由16位组成一串字帧。0 由 0.26ms的低电平和0.8ms的高电平表示, 1由 0.26ms的低电平和1.8的高电平表示。3 k' e2 ?& j, j  f$ Z, ]
两者的周期相差一倍,我把红外信号由红外接收头HS3818接收后送到STM8S的外部中断I/O上面,我是根据数据周期来判断是0% z2 c# n. F; C7 `' _: D
还是1的。( M% ~, Q# x0 _: |
w453509596 回答时间:2015-1-8 21:59:40

STM8S按键驱动

本帖最后由 w453509596 于 2015-1-9 11:30 编辑 4 k- i) W) k* l4 ]+ P

$ R/ H" h7 R6 b- W     按键分为独立按键和矩阵按键,矩阵按要比独立按键省I/O口,但是驱动程序要复杂。这两者各种有利有弊,那么有没有两者兼得的方法呢。如果的你的工程中有段式LED的话,恭喜你中奖了,看看我的方法吧。
, u, W4 B- ^, R9 J% C0 Y/ S, a    从我的测线板的原理图中可以看出,我在不增加I/O的情况下,让我的测线板多上了8个独立按键。那么如何驱动这8个独立按键呢。以前学
4 G5 A& _6 [, ?5 P的都是,先判断到有按键按下,再等10ms,如果按键还是按下的,则置下按键按下标志。那么问题来了,10ms的延时(不符合节约的原则),还有
4 J$ q) ?3 N) m) f. q如果我的按是长按的怎么处理呢。我分享下我的方法。我也是在中断中处理的。
4 _/ x6 X9 \, |, {. E  Y4 ^    我会为什么时候执行显示,什么时候处理按键检测 排个次序。有点类似操作系统中的分时复用。现在把执行按检测的部分独立起来看。
2 ~9 _2 a: w7 z% I' B    每次执行按键检测的时候,我会先判断8个按键的状态,看看有没有被按下,如果没有,则不用理会。如果有,则记下一标记,下一次时中断,还5 @, Z0 b6 R" S  g2 ]
有按下,那好了,程序就认定有按键按下了,接下来的连续几次进中断,还是有按下,则认定它为长按了。我附上我的程序。/ o- |) W" S9 j6 s6 Z/ o' ^( Z  o7 f7 A

, h/ ^3 [, d2 n5 v0 U' q# N" r* q$ q* T3 L/ A
KEYStatusDef KEYStatus;     //按键的状态 分为三种: 没有按下;   已经按下了,等待下一个中断确认; 等待按键松开,或确认为长按
. [, t1 S6 J. X' D" JKEYValueDef  KEY_Value;& J2 b6 A. m: J6 ]% n
FunctionStatus KEY_Flag;
' U7 X9 a- q; D+ |) Wstatic Uint8  KEY_Temp1;
/ k, O1 r* o3 K5 M+ rstatic Uint8  KEY_Temp2; ! m1 O, T( ^9 C1 i# O

1 k: I* b5 h, R4 @  _static void KEY_PortScan(void)   // 从没有按键按下到按键的确认
2 r: y9 t* [, D6 O3 `5 g) B{
& g5 |, @7 v6 c  KEY_Temp1 = KEY_Data;
( e/ ]4 j( x, W) U7 p  if(KEY_Temp1 != 0xff) / r7 k1 _/ J. j" x6 J2 k9 o7 I7 A
  {   % H3 {4 {6 C; v1 E& m. l+ H4 }! o
    KEYStatus = KEYStatus_Ok;5 t$ L& e$ m9 w5 `1 N9 Q7 q0 {
  }5 J0 b: I4 {8 S& z
}
! V2 i4 J( e/ |# h) P5 x
/ m  Q9 \2 s# ystatic void KEY_PortOk(void)      //从确认按键下到等待按键的松开. w! t3 o; h2 F- R1 Y) R
{
9 ]' I4 I' D* A8 ]( A8 G  KEY_Temp2 = KEY_Data;: K; Z, |' X7 D9 L' g8 c
  if((KEY_Temp2 == KEY_Temp1)&&(KEY_Temp2 != 0xff))   //再次判断按键,如果值和上次相同,则认定有按键按下' t4 E/ [+ j9 {9 C5 G' w
  {
0 P' _5 @( ^3 v, h8 d    KEY_Value = (KEYValueDef)KEY_Temp2;         //保存按键值
' E% w+ L( A& P! L* _! Z( j    KEYStatus = KEYStatus_Pro;
8 ]: A' S+ Y8 x# K6 e- V, j! U    KEY_Flag = L_TRUE;                                      //置按键按下标志位1 ~( x. e/ L8 F) i" G/ G- M
  }else KEYStatus = KEYStatus_Scan;   5 n, J& f( q5 i, t! O- r
}9 B) @7 K& t1 q8 E3 {

: B3 k; R7 @, ]static void KEY_PortPro(void)      //判断按键的松开,去检测下一个按键的按下7 y4 F, J9 H0 Q
{
; E7 n; E8 X4 M5 B$ S5 @& q  KEY_Temp1 = KEY_Data;) j+ [! z* N) w, D5 u" z
  if(KEY_Temp1 == 0xff) KEYStatus = KEYStatus_Scan;5 I0 R, X+ j1 G# ]
  else /*判断按键 长按*/0 h$ w% \% D  V) Q' o6 Z: S
}4 u- f3 i8 L) s/ h% g

  y2 L: [1 q; c5 Lstatic void KEY_Scan(void)8 Z. \/ A. v* v: ~) x6 v; f
{3 [9 a4 V' K8 B( R4 S( N, a" s
  KEY_Input();                 // 置I/O为输入端口,用来检测按键输入功能( @& T4 \+ {* F. t8 k: z
//在主频比较大时,内核的处理速度大于I/O的处理速度,因为I/O最大输出速度只有10M,输入更低。STM8S最高主频有24M,这里加空操作,数量按实//际测试而定,我为工程的稳定性,很保留的加了10个nop();,5个也可以了。
/ a; z/ `0 o0 n! v3 ^( F#if UserSystemClock > 6      
, P4 E9 j5 A. L9 s  nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop(),nop();  
& P9 S" g( Q5 ]$ K9 V! a$ g( `* ^' w4 _#endif
6 `+ |! `- n4 @! }/ s3 c# |  if(KEYStatus == KEYStatus_Pro) KEY_PortPro();        //有按键按下,等待按键松开或按键长按认定% C$ T+ x7 {; y8 F$ N# p* U
  else if(KEYStatus == KEYStatus_Ok) KEY_PortOk();   //确认按键按下( S( R( }  b' \4 V3 F- F
  else KEY_PortScan();                                                 //扫描有没有按键按下,  这一个放在最后,用 else,也是为了让程序具有自动修复能力
# A( R$ C3 ^/ s+ ?: ~# b  KEY_Output();              //置I/O为输出端口,用于显示功能6 ?+ c& o9 w3 O- m( h
}
3 n2 M, f, W1 f+ G) f# ?8 n) |( [+ e+ {. @/ M2 J8 M
void KEY_Varible_Init(void)     //初始化按键相关变量的初始值.
. B4 o1 E. }% e3 `5 N/ w- g0 M{; y* J$ f' z4 [* ^5 e; q
  KEYStatus = KEYStatus_Scan; 3 K+ ^/ C& G3 H) R; e
  KEY_Value = KEYVal_NO;) A! L5 C6 ]7 |
  KEY_Temp1 = 0xff;
) a+ s* E7 e/ ^# p$ e# i5 H; M  KEY_Temp2 = 0xff;- k# L' Z0 G* e, _- u5 w
  KEY_Flag = L_FASE;5 D1 u% j5 d0 n3 C1 @; Z3 J) k
}- F5 O) [0 k1 ]& [
: u  U6 R. e4 [0 @# N

7 n: _' O- I. y上面的介绍只是代码部分,硬件部分有个地方大家要注意,就是那个按键公共端上面接了一个电阻R10。它取值很重要,为了防止在按键按下时,数码管对应的段不亮。综合下面的两点,我的板子上R10实际取的是2K;3 f3 D/ u8 V- w8 E

8 k' }! p/ R& ^4 c, L- N1  参考STM8SR207RB数据手册,STM8认定0.3VDD为低电平,保守一点,最好不要超过0.15倍VDD。而按的上接电阻是33K,其实有点大了,1 T) S6 F- W7 G, m4 v' a& j
    我实际焊板测试后,选取的是22K,因为这直接影响了前面判断按键状态的准确性,还有一点大家不要忽视了,芯片内部还有个上接电阻,% x2 A+ S0 `% R0 I% Q' M5 L1 F& S: W
   根据数据手册 上接电阻为30~80K.
( f* b" q; d# l2 数码管点亮它有一个压降(大家不要认数码管也是0.7V),大多数码管是2~3V的样了。所以数码管与单片机连接处加一个限流电阻,这个电
& E! i2 Z6 Y" m' _9 \5 q0 q   阻是多少?
) j: @) T; e, v+ c      a,数码管点亮2ma足够了。(5 - 3)/ 2 = 1K  ,尽可能的减小这个电流,单片机驱动能力是有限的
' M1 W0 ~) E# A) b% d      b , I/O输出的5V分在限流电阻和R10上,保证R10的电压大于3V。
- G$ |- Q' s9 C6 H3 k
) I% s8 s) I+ n% x$ H: N  A! l8 g" Q5 s. B* X

, y) m# l7 Z. l

端口电气特性

端口电气特性
w453509596 回答时间:2015-1-8 21:14:41
本帖最后由 w453509596 于 2015-1-8 21:09 编辑
: q& i; Q7 s; K# a- i% r) r9 u9 @2 J0 |. R2 \$ A8 O& H- G
     我的板子是我自己做的,上面有一个四位共阴数码管,8个LED和8个按键,一个蜂鸣器,一组测12根排线通断的接线口,一组用RS485芯片引出来的串口。我的板子的原理图和PCB我会在附件中提供。想要学习好STM8S单片机,大家也最好能有一块开发板,淘宝上卖的很便宜,少吃点香蕉就可以买到了,卖家还提供有很多的例程,个人建议大家买个简单的板子,有条件的话,建议自己做一个。
3 y$ L3 e+ P7 S9 p    目前STM8S的编程软件有 IAR FOR STM8  和官方的STVD ,个人强列推荐IAR FOR STM8,STVD比较难用,我两者都用过,现在一直在用 IAR FOR STM8 1.3(这个软件大家自己网上搜了,比超市里的香蕉还要多)。+ J% H: t; {/ h+ I# d& q. [
   我的板子用的芯片是STM8S207RB ,对应的数据手册和参考手册在这里直接下载。(https://www.stmcu.org.cn/document/list/index/category-17 ),第一个和第二个就是(RM0016 参考手册 和 DS5839 数据手册)。数据手册是介绍该芯片里面有哪些资源、片上外设供大家使用,以及它的电气参数(相当于超市里面挂在香蕉前面的牌子)。而参考手册刚是介绍如使用编程这款芯片了(其实这款芯片毕竟是8位单片机,入门也相对比较简单,祝大家早日能像吃香蕉一样简单的用它)。我的原理图和PCB是用 altium designer 9.3画的。
6 R/ E, S/ f2 G; W; x8 S& ~   还有个官方的STM8S /标准外围库:  https://www.stmcu.org.cn/document/li ... ew/category-504?p=2    (倒数第二个STSW-STM8069)
! z7 Y7 u' V3 F% r   如果你用到的芯片也是STM8S207RB的话,直接用我的附件的中的 工程模板就可以了。代码库中有帮助文挡和官方例程。
, `7 s+ x! B* A- p   最后还有个福利,标准外围库,中文函数生成器,在附件中(STM8S真是好,这也能有! ! ! 被天上的馅饼砸中了,满满的都是幸福! ! !)
4 o8 Z5 j9 O! y1 W, A/ 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
3 v, s% ~* e! o6 r/ z: q测线板是干什么用的?
* r* G7 [* F5 f  B
同问
( ~  E* {- L) C. z0 {- w4 D0 ]; H是不是类似网线那种, 通断显示
& \( h7 A" B5 j3 \& F  X) g
4 k$ k+ j# a8 I) I 111111.jpg 22222.png
2 H  z0 ~% x7 E
( y8 s  I  c' N
w453509596 回答时间:2015-1-8 21:57:07
jcrorxp 发表于 2015-1-8 21:48+ C. B, G) O' I4 O( p$ ]
同问( ~- P, i1 t7 w, a' e! O/ i/ k
是不是类似网线那种, 通断显示

! B3 J& B9 l1 j8 b- i- X, P是这样的一个功能。
w453509596 回答时间:2015-1-8 21:59:08

STM8s定时器的使用程序

本帖最后由 w453509596 于 2015-1-9 09:33 编辑 & p+ ]3 h/ v8 s$ a0 D& {* k

9 ?% X- b7 P! p. b  STM8S包含有三种定时器,高级定时器,通用定时器和基本定时器,这三种定时器在功能上是包含关系的。在这里做一段最简单的1ms的定时功能。5 F/ l5 g. r) q
  static void MCU_TIM2_Init(void)  //定时器2 1ms中断初始化0 M3 U8 b8 @# ]# J) g$ S
{6 j: p. h! O, H8 f# d( Z
  TIM2_DeInit();                                                                 //复位所有寄存器值,这一步呢可选,为了产品稳定性,最好还是选上
* v, \9 o5 w) W7 t$ \5 p& J  TIM2_TimeBaseInit(TIM2_PRESCALER_1, 0x07d0);          //2M 内部时钟,一分频 2000
& y6 p9 l- u0 ~5 U1 b0 |5 U  TIM2_UpdateDisableConfig(DISABLE);                             //允许更新    即是在每一次定时器溢出之后,会自动更新计数器
8 n1 V0 ?. C/ c3 z  TIM2_UpdateRequestConfig(TIM2_UPDATESOURCE_REGULAR);  //只允许规则请求更新,即是只允许定时器溢出更新
- @" m# F* B" D. \$ X  TIM2_ITConfig(TIM2_IT_UPDATE, ENABLE);                //打开定时器溢出中断
0 S2 [/ ?) A3 i2 I$ k  TIM2_Cmd(ENABLE);                                                   //启动定时器8 N0 x) r8 O# [' X1 R
}
3 b1 N+ N  N  R  k( \- j* F
7 Z. I6 G0 D% _5 {通过上面的一段程序即实现1ms 的定时功能 :我的这个示例是在默认的系统时钟,2M / 1000 = 2000 ,所以模寄存器的值0x07d0。大家是别的主频的' k+ Y2 q  M  m! i4 F& b7 i6 |
话,根据想要定时的周期,对应的调相关系数即可。有库函数用起来真的很简单。我再上传一个风驰大哥的教程。
+ f5 Y" J& h2 L! A4 V% L
. _8 X: p6 h1 o. \% F有了定时器的中断,必有中段函数,库模板已在库函数 stm8s_it.c中写好了
' B# B$ X: h/ R4 t# G INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13)  //定时器2溢出中断
4 Q: S/ n6 s, {* d3 g5 @& J' G {
" h- Q, Z! B3 E* }/ u, T* f- z, e   /*  用户函数*/
; C! S+ I- x1 ~5 T7 S- j. J  }% G   TIM2_ClearITPendingBit(TIM2_IT_UPDATE);          //清除定时器2溢出中断; p0 i. ~8 B$ T: X
}8 u$ [# o$ T$ n+ q
# w4 q4 o# K+ A4 J; s1 n
; \9 \0 a! `& d/ m0 ~+ F1 z. R

10-TIM1(定时).pdf

下载

428.3 KB, 下载次数: 73

TM1定时

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

数码管驱动

本帖最后由 w453509596 于 2015-1-9 09:58 编辑
8 m  ^5 _# h3 C4 R9 J2 ?$ T) {5 U/ ?, I$ @: t. ^) F
数码管驱动分为动态驱动和静态驱动。这里只讲我的动态驱动的设计方案供大家参考
' ?# \- `7 }/ e! ^1 }4 E' v5 L( w; _( X+ z我以前上学时老师教的动态驱动是这样的。
, R  P; [! z. H! Pvoid main(void)* q% ?1 ?  k& Z) p
{7 q; b: k6 u- \
    while(1)
! l" V* R8 X2 ]9 W    {
9 D; |7 W5 ]. E7 T; |        display_ONE();     //第一位数码管点亮
& k6 |2 E* K6 u0 x        delay_MS(10);     //延时个10ms
. q+ s9 Z  }; [        display_TWO();     //第一位数码管点亮
; p# c# N' u! V/ Z% V        delay_MS(10);
8 ^, h% r& x- W5 K        display_THR ();     //第一位数码管点亮
& E: i8 I6 _. z; y3 D$ M* H1 {        delay_MS(10);
  Y7 a; _" v/ n! v. e& y! M    }! x, ^3 x: K5 ^! H3 R8 u6 H% D/ h
}
" _+ J/ M+ ?4 F3 c6 P# P2 N  这样的写法只适用学习如何动态显示数码管,他有两个不足的地方,一个是延时函数浪费了很多处时器时间,另一个是如果这个循环中再加上别的任务,随着工程量的加大,数码管就会越来越暗,有时候甚至不亮了。那么怎么办呢,那就得要基于动态显示的原理进行改进了。在上一段中,介绍了定时器,我分享下我的方法。我是把 这段程序放在中断中。& U  D% `: a6 m& C
INTERRUPT_HANDLER(TIM2_UPD_OVF_BRK_IRQHandler, 13)
5 T7 H: {; C9 i& W' c3 y2 h{7 {+ c) e& A( v* L
  switch(Dispay_Index)                    
$ W$ P- B6 A8 s7 @9 X  ~  {
5 j. B8 I1 G9 I$ y" j8 l9 K      case 0: LED4_Disable();Dispay_Index = 1;LED_Data=LED_Buff[4];LED0_Enable();break;       //LED指示灯4 i9 p$ M0 X7 W! \. r: P: S' n
      case 1: LED0_Disable();Dispay_Index = 2;LED_Data=LED_Buff[0];LED1_Enable();break;       //第一位数码
" X# J+ [8 x9 i% N7 m/ h. O$ r      case 2: LED1_Disable();Dispay_Index = 3;LED_Data=LED_Buff[1];LED2_Enable();break;       //第二位数码
( @& \2 J& n+ \. A/ K  N3 W      case 3: LED2_Disable();Dispay_Index = 4;LED_Data=LED_Buff[2];LED3_Enable();break;       //第三位数码
+ ^/ \$ n; U! M6 [      case 4: LED3_Disable();Dispay_Index = 5;LED_Data=LED_Buff[3];LED4_Enable();break;       //第四位数码
! I1 v8 X/ f* j& |* w      default  : LED4_Disable();Dispay_Index = 0;KEY_Scan();break;    //扫描按键) ~/ n+ Y9 P0 B8 I) k
  }; P( X7 Z# x) [6 }/ b5 [, P
}$ m2 ^2 n7 B. G9 n3 I# N& D) z$ \% S. f
我的这段程序是这样的一个功能,每次进中断,更换显示一位数码管。在中断中可使数码管的显示与工程的主任务独立起来。不管其它地方如何变化,. ]- ?( ^) d" o
数码管的显示总会是稳定的。Dispay_Index 它是一个全局变量。如果临时变量的话,在退出中断时它的值就消失了。最后default建议大家一定要使( e# a! w' ]- A6 v1 G2 r; p9 {
用,因为它使得这个显示程序具有程序跑飞时的自我修正能力。由于我的LED和数码管是共用段码口的。所以我把LED就当作一位数码管来看待了。; L! t' ~, ]7 z+ F7 N( {5 T! ]
我的按键也是共用端口的,所以我也是把它当作一位数码管来看待的,只不过数码管是输出,它是输入而已。下一段我和大家分享一下我的按键驱动
- o% u5 j& [  U' Z5 z2 Y方法2 a& {& D4 V# m/ i5 n1 k3 i
  
. C1 x: c  |1 @9 u' R+ o  @  
4 `+ L) }7 i# n, [
+ A1 Z9 c5 \) l! L" Z8 @# u: R4 ]0 |. T+ h9 a7 t
* b& J5 p) M! S0 ^6 n& \9 p# T
w453509596 回答时间:2015-1-8 21:59:54

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

本帖最后由 w453509596 于 2015-1-9 11:57 编辑 8 H* ^7 V, F( G& L: n) v# p. Y

/ O# F* M6 B& u) g1 n1 P    在使用51单片机中,我们可以很方便的定义位  sbit  LED_0 = P0^1;
4 q- J( R1 [$ e5 [   但STM8S库和IAR并不支持这样的操作,这给我们在写应用代码时带来了很多不便。那我们只能对面STM8S的I/O寄存器进行重新封装了。% Q: d3 u- d/ h
   在正式写程序时,我们要了解结构体在内存分配时,内存是连续不断的一片。 结构体和联合体部分不太理解的同学大家网找找。
, I5 w* d2 c& v- r( d" `( U   先看库是如何封装I/O寄存器的。0 ?- F3 w9 E  M: N- ~3 e# V' H
   typedef struct GPIO_struct     //定义I/O结构体类型' ^$ L8 |" u1 D
{; }& w! b/ C. e. x  }
  __IO uint8_t ODR; //!< Output Data Register - D; O1 \2 J7 F! k+ O
  __IO uint8_t IDR; //!< Input Data Register 3 ?. y; Q: y( Q2 J6 R' S
  __IO uint8_t DDR; //!< Data Direction Register 4 X# r: B- d$ `  M5 ~% A* R6 |+ t
  __IO uint8_t CR1; //!< Configuration Register 1
$ p' r# z$ E8 r- k  __IO uint8_t CR2; //!< Configuration Register 2
* W; B, Z4 ~5 W, P  y }% t' x3 n* p, h: [
GPIO_TypeDef;  
. c2 f3 o# x" J9 S* R; r* v, M/ V- _/ L7 O1 [5 L
#define GPIOA ((GPIO_TypeDef *) GPIOA_BaseAddress)   //强制定义端口名& }2 _' @  w. D; o! N

2 J% k% {( |0 A' `# G! i" m      这样的话,我们想往 GPIOA上送数据,只要这样即可:
) l5 r/ M( a& O7 Q      GPIO->ODR = 0x01;        //即可轻松的为 GPIOA端口赋值了
. [4 m. G) f' L3 R& i* W" \* N9 N6 z% q7 d  h- ~, d# |8 ]
我们要如何封装呢。这是我现在用的。' n3 d5 q. Z2 C0 F2 J" K: R: b
typedef struct GPIOBIT_struct    //重新定义端口  因为一般只要用到数据输入和输出即可,我只定义了 ODR 和 IDR5 ^  F5 b  r. r: O4 g! P! @! l
{
# ~/ _* j$ G, }, g# c5 W& S( w' L union
; w0 F) i3 V9 j5 M& M4 R {7 G! G; b) r+ Z: a( z* j9 S. Y. X1 G
   __IO uint8_t    All;
: S* z8 Y6 _# i$ H5 [  |   struct
6 \3 }8 i- M0 ~, x   {3 o7 A6 r1 M& h+ @1 N
   __IO uint8_t B0:1;3 ~! Q9 s3 O  N# E) B. Z
   __IO uint8_t B1:1;+ e' q" ?+ t8 K. |
   __IO uint8_t B2:1;
9 X, n5 M# m, t% G1 b: M% ~( C/ |   __IO uint8_t B3:1;
7 n$ Z2 q% M9 \4 S) `, @+ d   __IO uint8_t B4:1;' ~& e7 k5 S( g2 Y  R: G
   __IO uint8_t B5:1;
  Q# \- G7 k+ w  }   __IO uint8_t B6:1;
6 ]' H" r8 F2 ]. H! n8 B* N  t& c4 n   __IO uint8_t B7:1;& X0 L2 I7 {4 a+ t) T3 Z
  }Bits;9 n0 K$ Q6 h8 T/ r1 }* B
}ODR,IDR;( u6 k: f$ ]. C1 |/ D
}GPIOBIT_TypeDef;3 ~, D5 F: P4 i' }# A" O$ |4 J

% z- L$ c$ u) a0 x#define GPIOANEW (*((GPIOBIT_TypeDef *) GPIOA_BaseAddress))) V0 ^: L( l) i
( j% f3 w7 F( J: E; ^8 i+ ?; `0 C
    这样将GPIOA重新命名为 GPIOANEW  现在往GPIOA口输出数据就可以样写了
* a. ~, v7 n) N    GPIOANEW->ODR.All = 0x01;
2 V8 H% N! C/ S5 R" H    单独往第1位写如何写呢? 如下即可。  z8 e+ p& H4 \8 z. ]
   GPIOANEW->ODR.Bits.B0 = 1  * I! }  ^  q; Q2 V6 h9 B4 m
. i7 g$ d. k9 K+ x% f; o+ C
   这样写是不是太麻烦呢,我们再封装它
2 |$ D& ]5 D, w: n/ J# ^   #define  GPIOA_0  GPIOANEW->ODR.Bits.B1& l  D& D, k# c% `& _/ H. J
    GPIOA_0 = 1;/ g- O' q8 ?7 Y2 C" [8 b7 G. q  X

/ }4 q: _  m5 D9 M" C关于它的位操作这么多也差不多够用了,其它大家自己多思考了
$ u# ]0 P9 |4 J
( y& e$ h( X+ |0 |. X  
) ]7 K! a8 Q0 h# _6 y9 q+ ]& o# L2 E, V6 }9 N" ]
% |+ u7 u; R8 @8 e

8 p4 v% C  U& |6 ?+ q
w453509596 回答时间:2015-1-8 22:00:11

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

本帖最后由 w453509596 于 2015-1-9 12:47 编辑
/ m9 ^' d4 g2 r3 x2 f( x: S4 ^) q4 A; ~
$ M5 m/ f9 L, J$ {0 x1 B( Y9 G5 }在测线程序设计之前,还是老样子,先想好这个用什么方法去测。2 q5 I1 h0 M& C& t- @9 N! w, B
在大批量生产排线的时候,一般会出现如下三种问题3 c+ e4 |7 x1 _* h
1.  线断了     2. 线交叉了     3.可能存在接触不良的情况2 ]( `4 e6 Z8 R) b3 s
如果用人眼去识别哪些线不好,哪些是好的。几根好办,几千条线呢,几万条怎么办呢。  只能借助自动化设备了。, K' J' }) Q" b6 o/ @+ F% D
6 v0 f- Y. ^& q6 ~6 M- h' S* M2 E- R
我呢提供一个我的思路。我还是放在中断当中去做。7 v  Z( f9 c8 W6 C+ y3 w( Z
第1次进中断,我给第1根线送一个低电平,再在线的另一端去检测它,将这个值保存在变量的第1位中,再将第1个端口复位为高电平
( z- P! C8 C  Z4 [% N8 S9 P 第2次进中断,我给第2根线送一个低电平,再在线的另一端去检测它,将这个值保存在变量的第2位中,再将第2个端口复位为高电平- \% U5 M! r' G. h* M, U
...
, I+ c1 W- }8 a4 y- @...) k$ _0 k* v2 G6 ]4 r3 e' [
第12次进中断,我给第12根线送一个低电平,再在线的另一端去检测它,将这个值保存在变量的第12位中,再将第12个端口复位为高电平. R7 U% E9 L8 h# i6 u1 N+ x
测完了12根线后。我判断这12根的状态,并保留下来。作一次测线计数。
; o3 A, c  R# J' {7 b0 A+ S9 k我们知道是线插上插座和拔下插座的过程中,这个状态是不稳定的。为了避免这个情况的误判, 我每次在测完12根线的循环之后,都记下它的
/ S. s% L- o: c( C$ z- J% v2 I6 [状态,直到10次连续测量的状态都是一样的,才最终认定这根线是好还是不好。7 e1 G% I% z; t9 e
1.  对于好的线,在数码管上面显示一个 PASS  表示通过
' k& x& t6 m1 K" W! J2.  那么对于不好的呢,找出是哪一根线不好,并把它在数码管上显示出来,让检测人员贴上标签,便于产线上工作人员维修
2 C- R  k  F, p; v/ v     如何算快速算这个线是哪一根呢?方法有很多种,1 B( Y! p1 Q1 x: q3 Y' l
     我用的是杳表法。把UCOSII当中 找最高优先级的表给复制过来就可以了。2 b. x2 ~  W; l" F3 q

8 d" i& m; P0 `是不是这样就算完了呢,为了使我们做出来的东西更像一个产品,我们还要给它润色。$ {6 Z" k, M$ V- f9 A+ m5 Q
  1. 我还会让产品计下测量多少个排线,产品的合格率是多少?
) v  _7 _& Y- @! S! h, Y' ?  2. 将最近10次的产品测量数据进行对比,看看产品的生产效率和合格的率情况,  便于提高生产 (STM8S有内部EEPROM,这些数必须保存在其中)
/ W) U5 o! I) w4 H; k  3. 根据其它产品的需要,我测的线肯定能只是12根的。 只要不超过12根,我们可以通过这个菜单去设定的% j" H" x: t2 S+ q, o4 W
  4. 可以通串口将这些数据上传到电脑上,结合上位机软件,将它们制表格% F+ R, o6 z6 y- u! q8 ?) o

9 X# _5 e; @. O" `+ K& L6 n/ V
1 y4 Z+ f( K  S+ B3 w6 p; A8 e如何去写这个菜单的结构,其实也有很多东西,大家可以在别处杳查。在8位机写一个很大的菜单,而且要有高的处理速度,我用是的结构体去做的,
( i) Y9 }+ F! r6 f7 `3 @6 A也是在网上的一位大哥的贴子上学的,可如今找不到连接了,它可以让一个10 x10 的菜单执行速度 和 1X 1速度一样快。/ _3 ^7 S* q& W: v+ w/ j
( X/ Z1 l# {9 }  V5 f
这个测线板本来是想写成教大家入门STM8S的,我不常写这一类文档。由于工作上比较忙,写着写着就变了。我更多的是写出了我平常工作中总结
/ `: T# Y+ ]6 v, b8 r5 \出来的比较好的程序设计思想。我把我的程序也上传过上来。4 f$ O4 h" H! L* l

2 x: V; K6 N" V& v- N' v个人写文档能力差,希望能有写文档能力强的朋友指导指导。俗话说: 会写画板子,会写程序的叫技术员; 会写报告、会做计划的是经理;  会做策划,会做方案的是老板。
( A# A7 F  f1 t# Y
- i5 n5 {4 `7 Y9 J  y. q3 w' i+ B* Y祝我们这些一心想学想做技术的朋友们早是成为老板!!!!
. _& b9 Y" X2 A& Z; H0 N. g2 ?) T1 c
( N$ B# m* |; A2 j
( v2 Z8 y  {7 R5 g# V0 o
' l. j: H, o# C: Z

测线板程序.rar

下载

413.18 KB, 下载次数: 55

测线板程序

aderson 回答时间:2015-1-8 22:08:02
那玩意儿就十块多钱一个有必要么。
0 F, [: q" _3 M  O0 e! X( F9 O
w453509596 回答时间:2015-1-9 13:00:31

基于UCOSII 的测线板程序

本帖最后由 w453509596 于 2015-1-9 13:07 编辑
: Y( H5 M. p1 m* D3 }. W* ?' r" f
& d2 e7 J7 u. p1 P: x+ R. f如果家能看我的贴子做出了这个测线板,那么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 编辑 : l( j4 i  |! X5 P1 A

( \; l3 z6 ]% c+ d+ T关于STM8S的看门狗,有一点非常要注意,它这个和我正常写看门狗不太一样。它要先开启看门狗,然后才能对看门狗进行配置,这一点官方的参考手册上标的不太明确
! K) n5 o7 J* GSTM8S的看门狗应该是这样的顺序8 C. d- B+ B( m1 @6 F5 A# x# Y
1 [% e; o# a0 l! F2 F/ S
static void MCU_IWOG_Init(void)   //看门狗初始化,只允许写一次
: @7 a! G8 x8 T7 h4 d{
/ e" S5 A8 s% H! `5 v3 ?  IWDG_Enable();                                //开看门狗1 c8 l9 ]4 z8 N: _
  IWDG_WriteAccessCmd(IWDG_WriteAccess_Enable); //写允许, I2 D# @- [" Y% _3 D  F6 N$ J2 y
  IWDG_SetPrescaler(IWDG_Prescaler_256);        //256分频' V& o8 @" w0 ~/ G- O
  IWDG_SetReload(0xfe);                         //254的重载值1 p1 y6 M1 ?6 Y, |6 S( }7 K  u
  IWDG_ReloadCounter();                         //刷新计数) j$ [0 L  h9 I/ G5 |; J
}
123下一页

所属标签

相似技术帖

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