Source code:
/*****************************************************
* main.c In it:
*****************************************************/
kd_init();
// ......
while (1)
{
if( should_update_kd )
{
kd_update();
}
// Other code
// ......
}
Look at the display and key scan source code:
/**********************************************************
* key_disp-config.h
******************************************************/
#ifndef _KEY_DISP_CFG_H_
#define _KEY_DISP_CFG_H_
#define DIGIT1 B, 0
#define DIGIT2 B, 1
#define DIGIT3 B, 2
#define DIGIT4 B, 3
#define KEY_FB D, 6
#define KD_CLR D, 7
#define KD_CLK B, 5
#define KD_DAT B, 4
#define KEY_NONE (uint8_t)(0xFF)
#define KEY_S1 (uint8_t)(0x01<<0)
#define KEY_S2 (uint8_t)(0x01<<1)
#define KEY_S3 (uint8_t)(0x01<<2)
#define KEY_S4 (uint8_t)(0x01<< 3)
#define KEY_S5 (uint8_t)(0x01<<4)
#define KEY_S6 (uint8_t)(0x01<<5)
#define KEY_S7 (uint8_t)(0x01<<6)
#define KEY_S8 (uint8_t)(0x01<<7)
#endif /*_KEY_DISP_CFG_H_*/******
/******************************
******************* key_disp.h
****************************************************/
#ifndef _KEY_DISP_H_
#define _KEY_DISP_H_
#include
#include "key_disp-config.h"
#define KD_CODE_NONE 10
#define KD_CODE_PAUSED 11
#define KD_CODE_CW 12
#define KD_CODE_CCW 13
#define KD_CODE_SET_RUN 14
#define KD_CODE_SET_SLEEP 15
#define KD_CODE_TIMER_RUN 16
#define KD_CODE_TIMER_SLEEP 17
#define KD_CODE_EXTERN_TRIG 18
#define KD_CODE_EXTERN_CTRL 19
#define KD_CODE_H 20
#define KD_CODE_M 21
#define KD_CODE_S 22
// Initialize key & display
void kd_init();
// Update key & display, MUST be called periodically, eg., in timer
void kd_update();
// Get key code
uint8_t kd_get_key();
// Set mode to display
void kd_display_code(uint8_t digit_id, uint8_t code_id);
// Set display digits, dp_pos=-1 means no dp displayed
void kd_display(uint16_t value, uint8_t max_digits, const int8_t dp_pos);
#endif /*_KEY_DISP_H_*/
/******************************************************
* key_disp.c
******************************************************/
#include "avr/io.h"
#include "key_disp.h"
#include "config.h"
#include "util.h"
#define NOP() asm volatile ("nop")
static const uint8_t seg_code[] =
{
0x3F/*0*/, 0x06/*1*/, 0x5B/*2*/, 0x4F/*3*/, 0x66/*4*/,
0x6D/*5*/, 0x7D/*6*/, 0x07/*7*/, 0x7F/*8*/, 0x6F/*9*/,
0x00/*KD_CODE_NONE*/,
0x73/*KD_CODE_PAUSED*/,
0x21/*KD_CODE_CW*/,
0x03/*KD_CODE_CCW*/,
0x50/*KD_CODE_SET_RUN*/,
0x6D/*KD_CODE_SET_SLEEP*/,
0x09/*KD_CODE_TIMER_RUN*/,
0x36/*KD_CODE_TIMER_SLEEP*/,
0x79/*KD_CODE_EXTERN_TRIG*/,
0x39/*KD_CODE_EXTERN_CTRL*/,
0x76/*KD_CODE_H*/,
0x20/*KD_CODE_M*/,
0x22/*KD_CODE_S*/,
};
#define SEG_DP 0x80
static volatile uint8_t _key_code = 0xFF;
static volatile uint8_t _digits[4];
void kd_init()
{
PORT_DDR_SET(DIGIT1);
PORT_DDR_SET(DIGIT2);
PORT_DDR_SET(DIGIT3);
PORT_DDR_SET(DIGIT4);
PORT_DDR_CLR(KEY_FB); // Input
PORT_DDR_SET(KD_CLR);
PORT_PIN_CLR(DIGIT1);
PORT_PIN_CLR(DIGIT2);
PORT_PIN_CLR(DIGIT3);
PORT_PIN_CLR(DIGIT4);
PORT_PIN_SET(KEY_FB); // Internal pull-up
PORT_PIN_SET(KD_CLR);
_digits[0] = _digits[1] = _digits[2] = _digits[3] = 0;
}
/* Takes about 50 us @ 8MHz */
void kd_update()
{
static uint8_t turn = 0;
uint8_t i;
if( turn++ & 0x01 )
return;
// Disable all digits first
PORT_PIN_CLR(DIGIT1);
PORT_PIN_CLR(DIGIT2);
PORT_PIN_CLR(DIGIT3);
PORT_PIN_CLR(DIGIT4);
if( turn++ & 0x02 )
{
//
// trun for key scan
//
uint8_t shift_data;
static uint8_t last_scan_code = 0;
static uint8_t last_code_count = 0;
//
// Scan key
PORT_PIN_CLR(KD_CLK);
PORT_PIN_CLR(KD_CLR);
PORT_PIN_SET(KD_CLR);
//
// All output 1
shift_data = 0xFF;
PORT_PIN_SET(KD_DAT);
while( shift_data )
{
// Pulse out
PORT_PIN_SET(KD_CLK);
PORT_PIN_CLR(KD_CLK);
shift_data >>= 1;
}
shift_data = 0x01;
while( shift_data )
{
if( (~shift_data) & 0x01 )
PORT_PIN_SET(KD_DAT);
else
PORT_PIN_CLR(KD_DAT);
// Pulse out
PORT_PIN_SET(KD_CLK);
PORT_PIN_CLR(KD_CLK);
// Delay
for( i=0; i<16; i++ )
NOP();
// Check feedback
if( PORT_PIN_VALUE(KEY_FB) == 0 )
{
if( last_scan_code == shift_data )
{
// Same as last scan result, that's the key!
if( last_code_count > 4 )
_key_code = shift_data;
if( last_code_count < 255 )
last_code_count++;
}
else
{
last_scan_code = shift_data;
last_code_count = 1;
_key_code = KEY_NONE;
}
break;
}
shift_data <<= 1;
}
if( shift_data == 0 )
{
_key_code = KEY_NONE;
last_scan_code = KEY_NONE;
last_code_count = 1;
}
}
else
{
//
// Turn for display
//
static uint8_t curr_digit = 0;
uint8_t curr_code = 0;
//
// Display digits
PORT_PIN_CLR(KD_CLK);
PORT_PIN_CLR(KD_CLR);
PORT_PIN_SET(KD_CLR);
curr_code = _digits[curr_digit];
for( i=0; i<8; i++ )
{
// MSB first
if( curr_code & 0x80 )
PORT_PIN_SET(KD_DAT);
else
PORT_PIN_CLR(KD_DAT);
curr_code <<= 1;
// Pulse out
PORT_PIN_SET(KD_CLK);
PORT_PIN_CLR(KD_CLK);
}
switch( curr_digit ) // 位控制pin可能不连续,所以不能够用移位之类的
{
case 0:
PORT_PIN_SET(DIGIT4);
break;
case 1:
PORT_PIN_SET(DIGIT3);
break;
case 2:
PORT_PIN_SET(DIGIT2);
break;
case 3:
PORT_PIN_SET(DIGIT1);
break;
}
// For next trun
curr_digit++;
curr_digit %= 4;
}
}
uint8_t kd_get_key()
{
return _key_code;
}
void kd_display_code(uint8_t digit_id, uint8_t code_id)
{
_digits[digit_id] = seg_code[code_id];
}
void kd_display(uint16_t value, uint8_t max_digits, const int8_t dp_pos/*=-1*/)
{
//
// Prepare seg code for LED
_digits[0] = seg_code[value % 10];
value /= 10;
_digits[1] = seg_code[value % 10];
if(max_digits > 2)
{
value /= 10;
_digits[2] = seg_code[value % 10];
if(max_digits > 3)
{
value /= 10;
_digits[3] = seg_code[value % 10];
}
}
if( dp_pos >=0 && dp_pos<3 )
_digits[dp_pos] |= SEG_DP;
}
Previous article:Super simple coding switch (single-button shuttle switch) decoding program
Next article:24c256 operation function, continuous read and write
Recommended ReadingLatest update time:2024-11-15 15:59
- Popular Resources
- Popular amplifiers
Professor at Beihang University, dedicated to promoting microcontrollers and embedded systems for over 20 years.
- LED chemical incompatibility test to see which chemicals LEDs can be used with
- Application of ARM9 hardware coprocessor on WinCE embedded motherboard
- What are the key points for selecting rotor flowmeter?
- LM317 high power charger circuit
- A brief analysis of Embest's application and development of embedded medical devices
- Single-phase RC protection circuit
- stm32 PVD programmable voltage monitor
- Introduction and measurement of edge trigger and level trigger of 51 single chip microcomputer
- Improved design of Linux system software shell protection technology
- What to do if the ABB robot protection device stops
- Huawei's Strategic Department Director Gai Gang: The cumulative installed base of open source Euler operating system exceeds 10 million sets
- Download from the Internet--ARM Getting Started Notes
- Learn ARM development(22)
- Learn ARM development(21)
- Learn ARM development(20)
- Learn ARM development(19)
- Learn ARM development(14)
- Learn ARM development(15)
- Analysis of the application of several common contact parts in high-voltage connectors of new energy vehicles
- Wiring harness durability test and contact voltage drop test method
- PD fast charging technology has been significantly updated, USB PD3.1 has been released, supporting 48V and 240W output
- Recording a newbie's understanding of RISC-V
- [GD32L233C-START Review] Driver for serial dot matrix display module
- Huawei Hongmeng was released yesterday, are you ready to upgrade???
- Cadence User Manual Classic
- The name of the SOLDER layer means soldering. Who translated it into solder mask?
- PYPL Programming Language Rankings for November 2022
- How can esp32 get the file information in the file system of the micropython task in another task?
- zstack protocol stack serial port problem
- [Summary of the shortlist] GigaDevice GD32L233 review event