STM8开发参考:
芯片寄存器文档
原理图
Google
1.GPIO工作模式
输入:
浮空输入
上拉输入
输出:
推挽输出
开漏输出
(1).浮空输入:浮空输入,可以做KEY识别,RX1
(2).带上拉输入:IO内部上拉电阻输入
(3).开漏输出:IO输出0接GND,IO输出1,悬空,需要外接上拉电阻,才能实现输出高电平。当输出为1时,IO口的状态由上拉电阻拉高电平,但由于是开漏输出模式,这样IO口也就可以由外部电路改变为低电平或不变。
(4).推挽输出:IO输出0-接GND,IO输出1 -接VCC,读输入值是未知的
2.软件配置
参考:STM8S中文书据手册、原理图、google
初始化流程:
cpu时钟初始化
IO输入输出选择
IO模式选择
IO输出/输入电平
(1).CPU时钟初始化(所有STM8工程,都需要先设置时钟)
内部时钟寄存器(CLK_ICKR):
高速内部RC振荡器使能
高速内部振荡器准备就绪
CLK_ICKR = 0x03;
时钟分频寄存器(CLK_CKDIVR):
CLK_CKDIVR = 0x01; //cpu work on 16/2=8MHz
(2).IO寄存器配置
a.IO输入输出选择:
端口x数据方向 (Px_DDR): x可以是A/B/C/D, 分别代表端口A/B/C/D
输入模式:
Px_DDR = 0x00; //端口x全部设置为输入模式
输出模式:
Px_DDR = 0x00; //端口x全部设置为输出模式
b.IO模式选择:
端口x控制寄存器1 (Px_CR1):
输入模式:
浮空输入:Px_CR1 = 0x00; //端口x全部设置为浮空输入
带上拉电阻输入:Px_CR1 = 0xFF; //端口x全部设置为带上拉电阻
输出模式:
模拟开漏输出:Px_CR1 = 0x00; //端口x全部设置为模拟开漏输出
推挽输出:Px_CR1 = 0xFF; //端口x全部设置为推挽输出
c.IO输入/输出电平:
端口x输入寄存器 (Px_IDR):
Input = Px_IDR & 1; //当Input 为0时,端口Px的第0位输入低电平
//当Input 为1时,端口Px的第0位输入高电平
端口x输出数据寄存器(Px_ODR):
Px_ODR |= 0xFF; //端口x全部输出高电平
Px_ODR &= 0xFF; //端口x全部输出低电平
3.附上源码
1.main.c
/* MAIN.C file
*
* Copyright (c) 2002-2005 STMicroelectronics
*/
#include <stdio.h>
#include "stm8s_type.h"
#include "stm8s103f.h"
#include "stm8s.h"
#include "gpio.h"
//test gpio
void test_gpio(void)
{
TGpioProperty Portx;
//PD3 上拉输出 低电平设置
Portx.port = PORTD; //选中端口
Portx.dir = 1; //输入、输出选择
Portx.mode = 1; //模式选择
Portx.index = 3; //端口那个
Portx.outlevel = 0; //输出时电平选择,输入模式无效
init_Pxx_as_gpio(Portx);
Portx.outlevel = 1;
set_Pxx_level(Portx);
}
int main(void)
{
bool PD3_level = 0;
TGpioProperty Portx;
CLK_ICKR = 0x03; /// open interval RTC and wakeup
/// set cpu freq.
CLK_CKDIVR = 0x00; //cpu work on 16MHz
delay_us(5000);
//test gpio
test_gpio();
Portx.port = PORTD;
Portx.dir = 0;
Portx.mode = 1;
Portx.index = 3;
Portx.outlevel = 0;
init_Pxx_as_gpio(Portx);
while (1)
{
PD3_level = get_Pxx_level(Portx);
if(PD3_level)
{
}
else
{
}
delay_us(1000000);
}
}
2.gpio.c
/*
* gpio.c
*
* Created on: Oct 25, 2019
* Author:
* Email :
*/
#include "stm8s.h"
#include "stm8s103f.h"
#include "gpio.h"
//GPIO输入输出
#define PADIR(dir, index) {dir == 0? (PA_DDR &= ~(1<<index)): (PA_DDR |= (1<<index));}
#define PBDIR(dir, index) {dir == 0? (PB_DDR &= ~(1<<index)): (PB_DDR |= (1<<index));}
#define PCDIR(dir, index) {dir == 0? (PC_DDR &= ~(1<<index)): (PC_DDR |= (1<<index));}
#define PDDIR(dir, index) {dir == 0? (PD_DDR &= ~(1<<index)): (PD_DDR |= (1<<index));}
//GPIO模式选择
#define PAMODE(mode, index) {mode == 0? (PA_CR1 &= ~(1<<index)): (PA_CR1 |= (1<<index));}
#define PBMODE(mode, index) {mode == 0? (PB_CR1 &= ~(1<<index)): (PB_CR1 |= (1<<index));}
#define PCMODE(mode, index) {mode == 0? (PC_CR1 &= ~(1<<index)): (PC_CR1 |= (1<<index));}
#define PDMODE(mode, index) {mode == 0? (PD_CR1 &= ~(1<<index)): (PD_CR1 |= (1<<index));}
//输出电平设置
#define PA_OLEVEL(dir, index, level) {dir == 1? (level == 0? (PA_ODR &= ~(1<<index)): (PA_ODR |= (1<<index))): PA_IDR;}
#define PB_OLEVEL(dir, index, level) {dir == 1? (level == 0? (PB_ODR &= ~(1<<index)): (PB_ODR |= (1<<index))): PB_IDR;}
#define PC_OLEVEL(dir, index, level) {dir == 1? (level == 0? (PC_ODR &= ~(1<<index)): (PC_ODR |= (1<<index))): PC_IDR;}
#define PD_OLEVEL(dir, index, level) {dir == 1? (level == 0? (PD_ODR &= ~(1<<index)): (PD_ODR |= (1<<index))): PD_IDR;}
//输入电平设置
#define PA_ILEVEL(index) (PA_IDR & (1<<index))
#define PB_ILEVEL(index) (PB_IDR & (1<<index))
#define PC_ILEVEL(index) (PC_IDR & (1<<index))
#define PD_ILEVEL(index) (PD_IDR & (1<<index))
void init_Pxx_as_gpio(TGpioProperty Portx)
{
switch(Portx.port)
{
case PORTA:
PADIR(Portx.dir, Portx.index);
PAMODE(Portx.mode, Portx.index);
PA_OLEVEL(Portx.dir, Portx.index, Portx.outlevel);
break;
case PORTB:
PBDIR(Portx.dir, Portx.index);
PBMODE(Portx.mode, Portx.index);
PB_OLEVEL(Portx.dir, Portx.index, Portx.outlevel);
break;
case PORTC:
PCDIR(Portx.dir, Portx.index);
PCMODE(Portx.mode, Portx.index);
PC_OLEVEL(Portx.dir, Portx.index, Portx.outlevel);
break;
case PORTD:
PDDIR(Portx.dir, Portx.index);
PDMODE(Portx.mode, Portx.index);
PD_OLEVEL(Portx.dir, Portx.index, Portx.outlevel);
break;
default:
break;
}
}
void set_Pxx_level(TGpioProperty Portx)
{
switch(Portx.port)
{
case PORTA:
PA_OLEVEL(Portx.dir, Portx.index, Portx.outlevel);
break;
case PORTB:
PB_OLEVEL(Portx.dir, Portx.index, Portx.outlevel);
break;
case PORTC:
PC_OLEVEL(Portx.dir, Portx.index, Portx.outlevel);
break;
case PORTD:
PD_OLEVEL(Portx.dir, Portx.index, Portx.outlevel);
break;
default:
break;
}
}
bool get_Pxx_level(TGpioProperty Portx)
{
bool level = 0;;
switch(Portx.port)
{
case PORTA:
level = PA_ILEVEL(Portx.index);
break;
case PORTB:
level = PB_ILEVEL(Portx.index);
break;
case PORTC:
level = PC_ILEVEL(Portx.index);
break;
case PORTD:
level = PD_ILEVEL(Portx.index);
break;
default:
break;
}
return level;
}
3.gpio.h
/*
* gpio.h
*
* Created on: Oct 25, 2019
* Author:
* Email :
*/
#ifndef DEVICE_GPIO_GPIO_H_
#define DEVICE_GPIO_GPIO_H_
#include <stdbool.h>
#define INPUT 0
#define OUTPUT 1
#define LOW_LEVEL 0
#define HIGHT_LEVEL 1
#define PushPullOutput 1
#define OpenDrainOutput 0
#define PullUpInput 1
#define FloatingiInput 0
typedef enum {
PORTA = 0,
PORTB = 1,
PORTC = 2,
PORTD = 3
}PORTx;
typedef struct _gpio_property
{
PORTx port; //A~D
bool dir; //INPUT 0, OUTPUT 1
unsigned char mode; //输入:上拉输入1 浮空输入 0; 输入:开漏输出0 推挽输出1
unsigned char index; //端口下标
unsigned char outlevel; //输出时电平选择,输入模式无效
}TGpioProperty, *PGpioProperty;
void init_Pxx_as_gpio(TGpioProperty Portx);
void set_Pxx_level(TGpioProperty Portx);
bool get_Pxx_level(TGpioProperty Portx);
#endif /* DEVICE_GPIO_GPIO_H_ */